summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-11-02 22:44:12 +0100
committerOndřej Surý <ondrej@sury.org>2011-11-02 22:44:12 +0100
commitc8d5977bb546dae9ed59d81556639c49badd8121 (patch)
tree4c86750db26c1c3502b60f2cd78ca9611cfa01d6
downloadknot-c8d5977bb546dae9ed59d81556639c49badd8121.tar.gz
Imported Upstream version 0.8.0~pre1upstream/0.8.0_pre1
-rw-r--r--AUTHORS5
-rw-r--r--COPYING674
-rw-r--r--ChangeLog0
-rw-r--r--CodingStyle77
-rw-r--r--Doxy.page.h88
-rw-r--r--Doxyfile1634
-rw-r--r--Doxyfile.devel1634
-rw-r--r--INSTALL365
-rw-r--r--KNOWN_ISSUES25
-rw-r--r--Knot.config1
-rw-r--r--Knot.creator1
-rw-r--r--Knot.files253
-rw-r--r--Knot.includes13
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.in708
-rw-r--r--NEWS0
-rw-r--r--README142
-rw-r--r--aclocal.m41020
-rwxr-xr-xconfig.guess1502
-rwxr-xr-xconfig.sub1714
-rwxr-xr-xconfigure15763
-rw-r--r--configure.ac141
-rwxr-xr-xdepcomp630
-rwxr-xr-xinstall-sh520
-rw-r--r--knot.sample.conf.in18
-rwxr-xr-xltmain.sh8413
-rw-r--r--m4/ax_check_compiler_flags.m478
-rw-r--r--m4/ax_ext.m4122
-rw-r--r--m4/ax_gcc_x86_cpuid.m465
-rw-r--r--m4/libtool.m47377
-rw-r--r--m4/ltoptions.m4368
-rw-r--r--m4/ltsugar.m4123
-rw-r--r--m4/ltversion.m423
-rw-r--r--m4/lt~obsolete.m492
-rwxr-xr-xmissing376
-rwxr-xr-xresource.sh30
-rw-r--r--samples/Makefile.am24
-rw-r--r--samples/Makefile.in385
-rw-r--r--samples/bogus25.com.zone16
-rw-r--r--samples/example.com.zone69
-rw-r--r--samples/example.com.zone.nsec3635
-rw-r--r--samples/example.com.zone.signed571
-rw-r--r--samples/knot.full.conf250
-rw-r--r--samples/knot.min.conf30
-rw-r--r--samples/knot.sample.conf.in18
-rwxr-xr-xscripts/parse_dump.py145
-rwxr-xr-xscripts/pcap2dnsp.py17
-rw-r--r--src/Makefile.am336
-rw-r--r--src/Makefile.in2396
-rw-r--r--src/common/WELL1024a.c116
-rw-r--r--src/common/WELL1024a.h32
-rw-r--r--src/common/acl.c185
-rw-r--r--src/common/acl.h138
-rw-r--r--src/common/base32.c539
-rw-r--r--src/common/base32.h121
-rw-r--r--src/common/base32hex.c562
-rw-r--r--src/common/base32hex.h124
-rw-r--r--src/common/crc.c155
-rw-r--r--src/common/crc.h110
-rw-r--r--src/common/dynamic-array.c224
-rw-r--r--src/common/dynamic-array.h156
-rw-r--r--src/common/errors.c74
-rw-r--r--src/common/errors.h80
-rw-r--r--src/common/evqueue.c130
-rw-r--r--src/common/evqueue.h200
-rw-r--r--src/common/evsched.c309
-rw-r--r--src/common/evsched.h240
-rw-r--r--src/common/fdset.c80
-rw-r--r--src/common/fdset.h196
-rw-r--r--src/common/fdset_epoll.c216
-rw-r--r--src/common/fdset_epoll.h133
-rw-r--r--src/common/fdset_kqueue.c251
-rw-r--r--src/common/fdset_kqueue.h133
-rw-r--r--src/common/fdset_poll.c230
-rw-r--r--src/common/fdset_poll.h133
-rw-r--r--src/common/general-tree.c215
-rw-r--r--src/common/general-tree.h73
-rw-r--r--src/common/latency.c197
-rw-r--r--src/common/latency.h115
-rw-r--r--src/common/libtap/README231
-rw-r--r--src/common/libtap/tap.c313
-rw-r--r--src/common/libtap/tap.h101
-rw-r--r--src/common/libtap/tap_unit.h94
-rw-r--r--src/common/lists.c160
-rw-r--r--src/common/lists.h103
-rw-r--r--src/common/modified_tree.h292
-rw-r--r--src/common/print.c57
-rw-r--r--src/common/print.h72
-rw-r--r--src/common/ref.c44
-rw-r--r--src/common/ref.h90
-rw-r--r--src/common/skip-list.c437
-rw-r--r--src/common/skip-list.h215
-rw-r--r--src/common/slab/alloc-common.h61
-rw-r--r--src/common/slab/malloc.c60
-rw-r--r--src/common/slab/malloc.h43
-rw-r--r--src/common/slab/slab.c732
-rw-r--r--src/common/slab/slab.h353
-rw-r--r--src/common/sockaddr.c174
-rw-r--r--src/common/sockaddr.h120
-rw-r--r--src/common/tree.h268
-rw-r--r--src/config.h.in307
-rw-r--r--src/knot/common.h133
-rw-r--r--src/knot/conf/cf-lex.l218
-rw-r--r--src/knot/conf/cf-parse.y646
-rw-r--r--src/knot/conf/conf.c715
-rw-r--r--src/knot/conf/conf.h361
-rw-r--r--src/knot/conf/logconf.c102
-rw-r--r--src/knot/conf/logconf.h45
-rw-r--r--src/knot/ctl/knotc_main.c658
-rw-r--r--src/knot/ctl/process.c126
-rw-r--r--src/knot/ctl/process.h88
-rw-r--r--src/knot/main.c336
-rw-r--r--src/knot/other/debug.h426
-rw-r--r--src/knot/other/error.c46
-rw-r--r--src/knot/other/error.h99
-rw-r--r--src/knot/other/log.c305
-rw-r--r--src/knot/other/log.h208
-rw-r--r--src/knot/server/dthreads.c1006
-rw-r--r--src/knot/server/dthreads.h353
-rw-r--r--src/knot/server/journal.c636
-rw-r--r--src/knot/server/journal.h243
-rw-r--r--src/knot/server/notify.c327
-rw-r--r--src/knot/server/notify.h128
-rw-r--r--src/knot/server/server.c730
-rw-r--r--src/knot/server/server.h211
-rw-r--r--src/knot/server/socket.c192
-rw-r--r--src/knot/server/socket.h120
-rw-r--r--src/knot/server/tcp-handler.c511
-rw-r--r--src/knot/server/tcp-handler.h103
-rw-r--r--src/knot/server/udp-handler.c438
-rw-r--r--src/knot/server/udp-handler.h74
-rw-r--r--src/knot/server/xfr-handler.c1296
-rw-r--r--src/knot/server/xfr-handler.h163
-rw-r--r--src/knot/server/zones.c2352
-rw-r--r--src/knot/server/zones.h264
-rw-r--r--src/knot/stat/gatherer.c77
-rw-r--r--src/knot/stat/gatherer.h110
-rw-r--r--src/knot/stat/stat-common.h46
-rw-r--r--src/knot/stat/stat.c270
-rw-r--r--src/knot/stat/stat.h157
-rw-r--r--src/knot/zone/zone-dump-text.c1083
-rw-r--r--src/knot/zone/zone-dump-text.h46
-rw-r--r--src/knot/zone/zone-dump.c2301
-rw-r--r--src/knot/zone/zone-dump.h94
-rw-r--r--src/knot/zone/zone-load.c1209
-rw-r--r--src/knot/zone/zone-load.h104
-rw-r--r--src/knotc.863
-rw-r--r--src/knotd.835
-rw-r--r--src/libknot/common.h105
-rw-r--r--src/libknot/consts.h108
-rw-r--r--src/libknot/dname.c1070
-rw-r--r--src/libknot/dname.h428
-rw-r--r--src/libknot/edns.c416
-rw-r--r--src/libknot/edns.h273
-rw-r--r--src/libknot/hash/cuckoo-hash-table.c1688
-rw-r--r--src/libknot/hash/cuckoo-hash-table.h333
-rw-r--r--src/libknot/hash/hash-functions.c241
-rw-r--r--src/libknot/hash/hash-functions.h85
-rw-r--r--src/libknot/hash/universal-system.c116
-rw-r--r--src/libknot/hash/universal-system.h109
-rw-r--r--src/libknot/libknot.h48
-rw-r--r--src/libknot/nameserver/name-server.c3663
-rw-r--r--src/libknot/nameserver/name-server.h358
-rw-r--r--src/libknot/nsec3.c265
-rw-r--r--src/libknot/nsec3.h92
-rw-r--r--src/libknot/packet/packet.c1532
-rw-r--r--src/libknot/packet/packet.h538
-rw-r--r--src/libknot/packet/query.c228
-rw-r--r--src/libknot/packet/query.h93
-rw-r--r--src/libknot/packet/response.c1170
-rw-r--r--src/libknot/packet/response.h198
-rw-r--r--src/libknot/rdata.c838
-rw-r--r--src/libknot/rdata.h339
-rw-r--r--src/libknot/rrset.c719
-rw-r--r--src/libknot/rrset.h306
-rw-r--r--src/libknot/tsig-op.c1089
-rw-r--r--src/libknot/tsig-op.h161
-rw-r--r--src/libknot/tsig.c618
-rw-r--r--src/libknot/tsig.h145
-rw-r--r--src/libknot/updates/changesets.c296
-rw-r--r--src/libknot/updates/changesets.h102
-rw-r--r--src/libknot/updates/ddns.c638
-rw-r--r--src/libknot/updates/ddns.h74
-rw-r--r--src/libknot/updates/xfr-in.c3013
-rw-r--r--src/libknot/updates/xfr-in.h184
-rw-r--r--src/libknot/util/debug.c233
-rw-r--r--src/libknot/util/debug.h755
-rw-r--r--src/libknot/util/descriptor.c501
-rw-r--r--src/libknot/util/descriptor.h332
-rw-r--r--src/libknot/util/error.h87
-rw-r--r--src/libknot/util/libknot_error.c53
-rw-r--r--src/libknot/util/tolower.c276
-rw-r--r--src/libknot/util/tolower.h57
-rw-r--r--src/libknot/util/utils.c127
-rw-r--r--src/libknot/util/utils.h196
-rw-r--r--src/libknot/util/wire.h926
-rw-r--r--src/libknot/zone/dname-table.c310
-rw-r--r--src/libknot/zone/dname-table.h168
-rw-r--r--src/libknot/zone/node.c906
-rw-r--r--src/libknot/zone/node.h436
-rw-r--r--src/libknot/zone/zone-contents.c2396
-rw-r--r--src/libknot/zone/zone-contents.h556
-rw-r--r--src/libknot/zone/zone-tree.c470
-rw-r--r--src/libknot/zone/zone-tree.h300
-rw-r--r--src/libknot/zone/zone.c246
-rw-r--r--src/libknot/zone/zone.h157
-rw-r--r--src/libknot/zone/zonedb.c389
-rw-r--r--src/libknot/zone/zonedb.h145
-rw-r--r--src/tests/README10
-rw-r--r--src/tests/common/acl_tests.c111
-rw-r--r--src/tests/common/acl_tests.h25
-rw-r--r--src/tests/common/da_tests.c330
-rw-r--r--src/tests/common/da_tests.h25
-rw-r--r--src/tests/common/events_tests.c192
-rw-r--r--src/tests/common/events_tests.h25
-rw-r--r--src/tests/common/fdset_tests.c177
-rw-r--r--src/tests/common/fdset_tests.h25
-rw-r--r--src/tests/common/skiplist_tests.c198
-rw-r--r--src/tests/common/skiplist_tests.h25
-rw-r--r--src/tests/common/slab_tests.c141
-rw-r--r--src/tests/common/slab_tests.h25
-rw-r--r--src/tests/files/sample_conf59
-rw-r--r--src/tests/knot/conf_tests.c141
-rw-r--r--src/tests/knot/conf_tests.h25
-rw-r--r--src/tests/knot/dthreads_tests.c392
-rw-r--r--src/tests/knot/dthreads_tests.h25
-rw-r--r--src/tests/knot/journal_tests.c184
-rw-r--r--src/tests/knot/journal_tests.h25
-rw-r--r--src/tests/knot/server_tests.c113
-rw-r--r--src/tests/knot/server_tests.h25
-rw-r--r--src/tests/libknot/files/parsed_databin0 -> 71188 bytes
-rw-r--r--src/tests/libknot/files/parsed_data_queriesbin0 -> 1325 bytes
-rw-r--r--src/tests/libknot/files/raw_databin0 -> 72100 bytes
-rw-r--r--src/tests/libknot/files/raw_data_queriesbin0 -> 1387 bytes
-rw-r--r--src/tests/libknot/libknot/cuckoo_tests.c382
-rw-r--r--src/tests/libknot/libknot/cuckoo_tests.h25
-rw-r--r--src/tests/libknot/libknot/dname_table_tests.c393
-rw-r--r--src/tests/libknot/libknot/dname_table_tests.h25
-rw-r--r--src/tests/libknot/libknot/dname_tests.c877
-rw-r--r--src/tests/libknot/libknot/dname_tests.h25
-rw-r--r--src/tests/libknot/libknot/edns_tests.c596
-rw-r--r--src/tests/libknot/libknot/edns_tests.h34
-rw-r--r--src/tests/libknot/libknot/node_tests.c344
-rw-r--r--src/tests/libknot/libknot/node_tests.h25
-rw-r--r--src/tests/libknot/libknot/nsec3_tests.c252
-rw-r--r--src/tests/libknot/libknot/nsec3_tests.h25
-rw-r--r--src/tests/libknot/libknot/packet_tests.c430
-rw-r--r--src/tests/libknot/libknot/packet_tests.h25
-rw-r--r--src/tests/libknot/libknot/query_tests.c160
-rw-r--r--src/tests/libknot/libknot/query_tests.h25
-rw-r--r--src/tests/libknot/libknot/rdata_tests.c954
-rw-r--r--src/tests/libknot/libknot/rdata_tests.h52
-rw-r--r--src/tests/libknot/libknot/response_tests.c450
-rw-r--r--src/tests/libknot/libknot/response_tests.h25
-rw-r--r--src/tests/libknot/libknot/rrset_tests.c888
-rw-r--r--src/tests/libknot/libknot/rrset_tests.h34
-rw-r--r--src/tests/libknot/libknot/zone_tests.c853
-rw-r--r--src/tests/libknot/libknot/zone_tests.h25
-rw-r--r--src/tests/libknot/libknot/zone_tree_tests.c758
-rw-r--r--src/tests/libknot/libknot/zone_tree_tests.h25
-rw-r--r--src/tests/libknot/libknot/zonedb_tests.c44
-rw-r--r--src/tests/libknot/libknot/zonedb_tests.h25
-rw-r--r--src/tests/libknot/realdata/files/parsed_databin0 -> 4851 bytes
-rw-r--r--src/tests/libknot/realdata/files/parsed_data_queriesbin0 -> 1325 bytes
-rw-r--r--src/tests/libknot/realdata/files/raw_databin0 -> 4935 bytes
-rw-r--r--src/tests/libknot/realdata/files/raw_data_queriesbin0 -> 1387 bytes
-rw-r--r--src/tests/libknot/realdata/libknot/dname_tests_realdata.c411
-rw-r--r--src/tests/libknot/realdata/libknot/dname_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/edns_tests_realdata.c563
-rw-r--r--src/tests/libknot/realdata/libknot/edns_tests_realdata.h35
-rw-r--r--src/tests/libknot/realdata/libknot/node_tests_realdata.c385
-rw-r--r--src/tests/libknot/realdata/libknot/node_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/packet_tests_realdata.c679
-rw-r--r--src/tests/libknot/realdata/libknot/packet_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/rdata_tests_realdata.c329
-rw-r--r--src/tests/libknot/realdata/libknot/rdata_tests_realdata.h53
-rw-r--r--src/tests/libknot/realdata/libknot/response_tests_realdata.c173
-rw-r--r--src/tests/libknot/realdata/libknot/response_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/rrset_tests_realdata.c289
-rw-r--r--src/tests/libknot/realdata/libknot/rrset_tests_realdata.h35
-rw-r--r--src/tests/libknot/realdata/libknot/zone_tests_realdata.c335
-rw-r--r--src/tests/libknot/realdata/libknot/zone_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c44
-rw-r--r--src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h25
-rw-r--r--src/tests/libknot/realdata/libknot_tests_loader_realdata.c1300
-rw-r--r--src/tests/libknot/realdata/libknot_tests_loader_realdata.h179
-rw-r--r--src/tests/libknot/realdata/unittests_libknot_realdata.c93
-rw-r--r--src/tests/libknot/unittests_libknot.c90
-rw-r--r--src/tests/unittests_main.c84
-rw-r--r--src/zcompile/LICENSE30
-rw-r--r--src/zcompile/parser-descriptor.c535
-rw-r--r--src/zcompile/parser-descriptor.h278
-rw-r--r--src/zcompile/parser-util.c2435
-rw-r--r--src/zcompile/parser-util.h357
-rw-r--r--src/zcompile/tests/unittests_zp_main.c62
-rw-r--r--src/zcompile/tests/zcompile_tests.c425
-rw-r--r--src/zcompile/zcompile-error.c52
-rw-r--r--src/zcompile/zcompile-error.h90
-rw-r--r--src/zcompile/zcompile.c639
-rw-r--r--src/zcompile/zcompile.h207
-rw-r--r--src/zcompile/zcompile_main.c116
-rw-r--r--src/zcompile/zlexer.l531
-rw-r--r--src/zcompile/zparser.y1730
-rw-r--r--tests/querytcp.c797
-rwxr-xr-xylwrap222
305 files changed, 133445 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..c032e47
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+Ľuboš Slovák <lubos.slovak@nic.cz>
+Marek Vavruša <marek.vavrusa@nic.cz>
+Jan Kadlec <jan.kadlec@nic.cz>
+Ondřej Surý <ondrej.sury@nic.cz>
+Ondřej Filip <ondrej.filip@nic.cz>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/CodingStyle b/CodingStyle
new file mode 100644
index 0000000..986417c
--- /dev/null
+++ b/CodingStyle
@@ -0,0 +1,77 @@
+Coding style
+============
+* Indentation: TAB (8 spaces width)
+* Braces: K&R, 1TBS
+* Max line width: 80 chars
+* Pointer asterisk attached to the name of the variable
+* Own structures/types: _t suffix (f.e. nameserver_t)
+* Header guard format: _KNOTD__HEADER_H_
+* Spaces around binary operators
+* Space between keyword and bracket (f.e. "if (predicate)")
+* No space between variable and typecast (f.e. "return (int)val;")
+
+To sum it up, Linux KNF is used, see [1].
+
+[1] Linux Coding Style:
+ http://kerneltrap.org/files/Jeremy/CodingStyle.txt
+
+AStyle command format
+=====================
+astyle --style=1tbs -t8 -w -p -H -U -j --align-pointer=name
+
+Doxygen
+=======
+* Format: Qt-style
+ * "\brief", not "@brief"
+ * "/*!", not "/**"
+* Order of sections
+ * brief description
+ * long description
+ * notes
+ * warnings
+ * parameters
+ * return values
+ * todos
+* Always use \brief (no autobrief)
+* Indent text (using spaces only) in multiple-line sections
+* In multi-line comments, opening line (/*!) should be empty
+* One empty line between two consecutive sections
+* Struct and union members documented on the same line if the comment fits
+* Use \retval (or more of them) instead of \return
+ if the function returns some distinct values
+ (such as 0 for no error, -1 for something else, etc.)
+
+Example
+=======
+/*!
+ * \brief Some structure.
+ *
+ * Longer description.
+ */
+ struct some_struct {
+ /*!
+ * \brief This comment does not fit on the same line as the member
+ * as it is rather large.
+ */
+ int fd;
+ int flags; /*!< Flags. */
+ };
+
+/*!
+ * \brief Brief description of some function.
+ *
+ * Longer description.
+ *
+ * \note This function is deprecated.
+ *
+ * \warning Do not use this function!
+ *
+ * \param param1 Some parameter.
+ * \param param2 Other parameter. This one has rather large comment,
+ * so its next line is indented for better readability.
+ *
+ * \retval 0 on success.
+ * \retval -1 if some error occured.
+ *
+ * \todo Remove (deprecated).
+ */
diff --git a/Doxy.page.h b/Doxy.page.h
new file mode 100644
index 0000000..4d0704c
--- /dev/null
+++ b/Doxy.page.h
@@ -0,0 +1,88 @@
+/*!
+
+\defgroup server Server control module.
+\defgroup threading Threading API.
+\defgroup network Socket API.
+\defgroup query_processing DNS query processing.
+\defgroup utils Utilities, constants and macros.
+\defgroup debugging Server debugging API.
+\defgroup logging Server logging API.
+\defgroup statistics Statistics module (optional).
+\defgroup dnslib dnslib - Generic DNS library.
+\defgroup hashing Hash table and functions.
+\defgroup common_lib Common library.
+\defgroup alloc Memory allocation.
+\defgroup tests Unit tests.
+\defgroup zoneparser Zone compiler utility
+\defgroup ctl Control utility
+
+\mainpage Knot API documentation.
+
+Knot is an open-source, high-performace, purely authoritative DNS server.
+
+<h2>Requirements</h2>
+- liburcu (at least 0.4.5): http://lttng.org/urcu
+- automake
+- autoconf
+- libtool
+
+<h2>Installation</h2>
+Knot uses autotools to generate makefiles.
+
+\todo Add some more info about usage and requirements.
+
+\code
+$ autoreconf -i
+$ ./configure
+$ make
+\endcode
+
+<h2>Starting the server</h2>
+
+When compiled, the following executables are created (in the src/ directory):
+- \em knotd - The server
+- \em knotc - Control utility
+- \em knot-zcompile - Zone compiler
+- \em unittests - Unit tests for the server and dnslib
+- \em unittests-zcompile - Unit tests for the zone compiler
+
+1. Add path to knotd and knot-zcompile executables to PATH
+
+2. Prepare a configuration file. You may copy and edit the one provided with
+ the server (\em samples/knot.conf.sample).
+
+2. Compile zone
+\code
+$ src/knotc -c path-to-config-file compile
+\endcode
+
+3. Run the server
+\code
+$ src/knotc -c path-to-config-file start
+\endcode
+
+<h2>Server modules</h2>
+- \ref server
+- \ref threading
+- \ref network
+- \ref query_processing
+- \ref utils
+- \ref debugging
+- \ref logging
+- \ref statistics
+
+<h2>DNS library</h2>
+
+- \ref dnslib
+- \ref hashing
+
+<h2>Common library</h2>
+
+- \ref common_lib
+- \ref alloc
+
+<h2>Other modules</h2>
+- \ref tests
+- \ref zoneparser
+- \ref ctl
+ */
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..4966e80
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1634 @@
+# Doxyfile 1.7.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# 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 (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+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.
+
+PROJECT_NAME = Knot
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.1.0
+
+# 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
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# 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,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# 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.
+
+STRIP_FROM_PATH = \
+ src/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+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
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# 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
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+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, 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 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
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+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.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# 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
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# 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.
+# 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 rougly 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
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# 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.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# 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
+
+# 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
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+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 = 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
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = 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
+
+# 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
+
+# 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
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = 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.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+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 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
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 50
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+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 = YES
+
+# 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.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+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.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# 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
+
+# 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
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled 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
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = src/ \
+ Doxy.page.h
+
+# 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
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# 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
+
+FILE_PATTERNS = *.c \
+ *.h
+
+# 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.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# 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.
+
+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
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_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 all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# 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.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+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.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+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.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+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!
+
+HTML_STYLESHEET =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet 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
+
+# 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_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.
+
+HTML_ALIGN_MEMBERS = 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).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# 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
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# 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.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+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)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+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.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+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
+# 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>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# 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>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# 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.
+
+GENERATE_ECLIPSEHELP = NO
+
+# 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.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# 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.
+
+DISABLE_INDEX = 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.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# 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.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# 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
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# 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
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# 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
+
+# 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 = YES
+
+# 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 disadvances is 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
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+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
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+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
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# 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
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+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.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet 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.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+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.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+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.
+
+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.
+
+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:
+# 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.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# 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.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# 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 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.
+
+DOT_FONTNAME = FreeSans.ttf
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+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.
+
+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_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+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.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES 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.
+
+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.
+
+DOT_IMAGE_FORMAT = png
+
+# 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.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_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
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/Doxyfile.devel b/Doxyfile.devel
new file mode 100644
index 0000000..4b73045
--- /dev/null
+++ b/Doxyfile.devel
@@ -0,0 +1,1634 @@
+# Doxyfile 1.7.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# 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 (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+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.
+
+PROJECT_NAME = Knot
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.1.0
+
+# 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
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc-devel
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# 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,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# 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.
+
+STRIP_FROM_PATH = \
+ src/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+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
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# 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
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+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, 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 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
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+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.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# 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
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# 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.
+# 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 rougly 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
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# 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.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# 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
+
+# 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
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+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 = 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
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = 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
+
+# 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
+
+# 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
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = 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.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+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 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
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 50
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+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 = YES
+
+# 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.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+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.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# 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
+
+# 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
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled 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
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = src/ \
+ Doxy.page.h
+
+# 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
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# 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
+
+FILE_PATTERNS = *.c \
+ *.h
+
+# 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.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# 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.
+
+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
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_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 all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# 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.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+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.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+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.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+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!
+
+HTML_STYLESHEET =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet 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
+
+# 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_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.
+
+HTML_ALIGN_MEMBERS = 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).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# 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
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# 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.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+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)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+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.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+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
+# 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>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# 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>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# 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.
+
+GENERATE_ECLIPSEHELP = NO
+
+# 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.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# 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.
+
+DISABLE_INDEX = 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.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# 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.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# 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
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# 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
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# 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
+
+# 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 = YES
+
+# 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 disadvances is 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
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+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
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+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
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# 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
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+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.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet 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.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+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.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+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.
+
+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.
+
+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:
+# 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.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# 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.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# 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 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.
+
+DOT_FONTNAME = FreeSans.ttf
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+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.
+
+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_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+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.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES 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.
+
+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.
+
+DOT_IMAGE_FORMAT = png
+
+# 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.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_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
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..7d1c323
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package. Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the `make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type `make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior `make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type `make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide `make
+ distcheck', which can by used by developers to test that all other
+ targets like `make install' and `make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'. This
+is known as a "VPATH" build.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'. Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated. The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the `DESTDIR' variable. For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names. The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of `make' will be. For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
+a workaround. If GNU CC is not installed, it is therefore recommended
+to try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put `/usr/ucb' early in your `PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+ On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+ Print a summary of the options unique to this package's
+ `configure', and exit. The `short' variant lists options used
+ only in the top level, while the `recursive' variant lists options
+ also present in any nested packages.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names::
+ for more details, including other options available for fine-tuning
+ the installation locations.
+
+`--no-create'
+`-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/KNOWN_ISSUES b/KNOWN_ISSUES
new file mode 100644
index 0000000..85bb088
--- /dev/null
+++ b/KNOWN_ISSUES
@@ -0,0 +1,25 @@
+Features not supported
+======================
+
+Here is a list of the most notable features that are not supported in the
+current version of Knot.
+
+* IXFR
+* Dynamic updates
+* TSIG
+* Slave functionality (AXFR-in).
+* RRSet rotation
+* Root zone (Knot cannot serve the root zone)
+* Other DNS classes than IN (CH, CS, HS)
+* Unknown RR types (types in form TYPE1234)
+
+
+Known bugs
+==========
+
+* Certain malformed packets cause the server to crash.
+* Some actions may not be fully thread-safe (e.g. removing expired zone).
+* If some hashed domain name (NSEC3) contains other data than NSEC3 and RRSIG,
+ queries for this data will not be responded well (always answers NXDOMAIN).
+* Server fails to quit properly on some systems.
+
diff --git a/Knot.config b/Knot.config
new file mode 100644
index 0000000..8cec188
--- /dev/null
+++ b/Knot.config
@@ -0,0 +1 @@
+// ADD PREDEFINED MACROS HERE!
diff --git a/Knot.creator b/Knot.creator
new file mode 100644
index 0000000..e94cbbd
--- /dev/null
+++ b/Knot.creator
@@ -0,0 +1 @@
+[General]
diff --git a/Knot.files b/Knot.files
new file mode 100644
index 0000000..06fff5e
--- /dev/null
+++ b/Knot.files
@@ -0,0 +1,253 @@
+CodingStyle
+Makefile.am
+Doxy.page.h
+Doxyfile
+Doxyfile.devel
+configure.ac
+KNOWN_ISSUES
+README
+tests/querytcp.c
+libknot/Makefile.am
+libknot/libknot.h
+libknot/common.h
+libknot/dname.h
+libknot/dname.c
+libknot/rrset.h
+libknot/rrset.c
+libknot/rdata.h
+libknot/rdata.c
+libknot/edns.h
+libknot/edns.c
+libknot/nsec3.h
+libknot/nsec3.c
+libknot/consts.h
+libknot/hash/cuckoo-hash-table.c
+libknot/hash/cuckoo-hash-table.h
+libknot/hash/hash-functions.c
+libknot/hash/hash-functions.h
+libknot/hash/universal-system.c
+libknot/hash/universal-system.h
+libknot/nameserver/name-server.c
+libknot/nameserver/name-server.h
+libknot/packet/packet.h
+libknot/packet/packet.c
+libknot/packet/query.h
+libknot/packet/query.c
+libknot/packet/response.h
+libknot/packet/response.c
+libknot/updates/changesets.h
+libknot/updates/changesets.c
+libknot/updates/ddns.h
+libknot/updates/ddns.c
+libknot/updates/xfr-in.h
+libknot/updates/xfr-in.c
+libknot/util/wire.h
+libknot/util/debug.h
+libknot/util/debug.c
+libknot/util/tolower.h
+libknot/util/tolower.c
+libknot/util/utils.h
+libknot/util/utils.c
+libknot/util/descriptor.h
+libknot/util/descriptor.c
+libknot/util/error.c
+libknot/util/error.h
+libknot/zone/zonedb.h
+libknot/zone/zonedb.c
+libknot/zone/node.h
+libknot/zone/node.c
+libknot/zone/zone.h
+libknot/zone/zone.c
+libknot/zone/zone-contents.c
+libknot/zone/zone-contents.h
+libknot/zone/zone-tree.h
+libknot/zone/zone-tree.c
+libknot/zone/dname-table.h
+libknot/zone/dname-table.c
+src/Makefile.am
+src/common/slab/malloc.c
+src/common/slab/malloc.h
+src/common/slab/slab.c
+src/common/slab/slab.h
+src/common/slab/alloc-common.h
+src/common/libtap/tap.c
+src/common/libtap/tap.h
+src/common/libtap/tap_unit.h
+src/common/lists.h
+src/common/lists.c
+src/common/base32.h
+src/common/base32.c
+src/common/print.c
+src/common/print.h
+src/common/latency.c
+src/common/latency.h
+src/common/dynamic-array.c
+src/common/dynamic-array.h
+src/common/skip-list.c
+src/common/skip-list.h
+src/common/tree.h
+src/common/base32hex.h
+src/common/base32hex.c
+src/common/evqueue.c
+src/common/evqueue.h
+src/common/evsched.c
+src/common/evsched.h
+src/common/errors.h
+src/common/errors.c
+src/common/acl.c
+src/common/acl.h
+src/common/sockaddr.h
+src/common/sockaddr.c
+src/common/crc.c
+src/common/crc.h
+src/common/ref.c
+src/common/ref.h
+src/common/modified_tree.h
+src/common/general-tree.h
+src/common/general-tree.c
+src/common/WELL1024a.c
+src/common/WELL1024a.h
+src/common/fdset.h
+src/common/fdset.c
+src/common/fdset_poll.h
+src/common/fdset_poll.c
+src/common/fdset_epoll.h
+src/common/fdset_epoll.c
+src/common/fdset_kqueue.h
+src/common/fdset_kqueue.c
+src/zcompile/parser-descriptor.h
+src/zcompile/parser-descriptor.c
+src/zcompile/parser-util.h
+src/zcompile/parser-util.c
+src/zcompile/zcompile.c
+src/zcompile/zcompile.h
+src/zcompile/zparser.y
+src/zcompile/zlexer.l
+src/zcompile/zcompile-error.h
+src/zcompile/zcompile_main.c
+src/knot/common.h
+src/knot/main.c
+src/knot/ctl/knotc_main.c
+src/knot/ctl/process.c
+src/knot/ctl/process.h
+src/knot/other/debug.h
+src/knot/other/log.c
+src/knot/other/log.h
+src/knot/other/error.c
+src/knot/other/error.h
+src/knot/stat/gatherer.c
+src/knot/stat/gatherer.h
+src/knot/stat/stat.h
+src/knot/stat/stat.c
+src/knot/stat/stat-common.h
+src/knot/server/dthreads.c
+src/knot/server/dthreads.h
+src/knot/server/server.c
+src/knot/server/server.h
+src/knot/server/socket.c
+src/knot/server/socket.h
+src/knot/server/tcp-handler.c
+src/knot/server/tcp-handler.h
+src/knot/server/xfr-handler.c
+src/knot/server/xfr-handler.h
+src/knot/server/udp-handler.c
+src/knot/server/udp-handler.h
+src/knot/server/zones.c
+src/knot/server/zones.h
+src/knot/server/journal.c
+src/knot/server/journal.h
+src/knot/server/notify.c
+src/knot/server/notify.h
+src/knot/ctl/process.c
+src/knot/ctl/process.h
+src/knot/conf/cf-lex.l
+src/knot/conf/cf-parse.y
+src/knot/conf/conf.c
+src/knot/conf/conf.h
+src/knot/conf/logconf.c
+src/knot/conf/logconf.h
+src/knot/zone/zone-dump.c
+src/knot/zone/zone-dump.h
+src/knot/zone/zone-load.c
+src/knot/zone/zone-load.h
+src/knot/zone/zone-dump-text.h
+src/knot/zone/zone-dump-text.c
+src/zcompile/tests/unittests_zp_main.c
+src/zcompile/tests/zcompile_tests.c
+src/zcompile/zcompile-error.c
+src/tests/unittests_main.c
+src/tests/common/acl_tests.c
+src/tests/common/acl_tests.h
+src/tests/common/da_tests.c
+src/tests/common/da_tests.h
+src/tests/common/events_tests.c
+src/tests/common/events_tests.h
+src/tests/common/skiplist_tests.c
+src/tests/common/skiplist_tests.h
+src/tests/common/slab_tests.c
+src/tests/common/slab_tests.h
+src/tests/common/fdset_tests.c
+src/tests/common/fdset_tests.h
+src/tests/knot/dthreads_tests.c
+src/tests/knot/dthreads_tests.h
+src/tests/knot/conf_tests.c
+src/tests/knot/conf_tests.h
+src/tests/knot/journal_tests.c
+src/tests/knot/journal_tests.h
+src/tests/knot/server_tests.c
+src/tests/knot/server_tests.h
+src/tests/libknot/unittests_libknot.c
+src/tests/libknot/libknot/dname_tests.c
+src/tests/libknot/libknot/dname_tests.h
+src/tests/libknot/libknot/edns_tests.c
+src/tests/libknot/libknot/edns_tests.h
+src/tests/libknot/libknot/node_tests.c
+src/tests/libknot/libknot/node_tests.h
+src/tests/libknot/libknot/rdata_tests.c
+src/tests/libknot/libknot/rdata_tests.h
+src/tests/libknot/libknot/response_tests.c
+src/tests/libknot/libknot/response_tests.h
+src/tests/libknot/libknot/rrset_tests.c
+src/tests/libknot/libknot/rrset_tests.h
+src/tests/libknot/libknot/zone_tests.c
+src/tests/libknot/libknot/zone_tests.h
+src/tests/libknot/libknot/zonedb_tests.c
+src/tests/libknot/libknot/zonedb_tests.h
+src/tests/libknot/libknot/cuckoo_tests.c
+src/tests/libknot/libknot/cuckoo_tests.h
+src/tests/libknot/libknot/dname_table_tests.h
+src/tests/libknot/libknot/dname_table_tests.c
+src/tests/libknot/libknot/packet_tests.c
+src/tests/libknot/libknot/packet_tests.h
+src/tests/libknot/libknot/query_tests.c
+src/tests/libknot/libknot/query_tests.h
+src/tests/libknot/libknot/nsec3_tests.c
+src/tests/libknot/libknot/nsec3_tests.h
+src/tests/libknot/realdata/unittests_libknot_realdata.c
+src/tests/libknot/realdata/libknot/packet_tests_realdata.c
+src/tests/libknot/realdata/libknot/packet_tests_realdata.h
+src/tests/libknot/realdata/libknot/dname_tests_realdata.c
+src/tests/libknot/realdata/libknot/dname_tests_realdata.h
+src/tests/libknot/realdata/libknot/edns_tests_realdata.c
+src/tests/libknot/realdata/libknot/edns_tests_realdata.h
+src/tests/libknot/realdata/libknot/node_tests_realdata.c
+src/tests/libknot/realdata/libknot/node_tests_realdata.h
+src/tests/libknot/realdata/libknot/rdata_tests_realdata.c
+src/tests/libknot/realdata/libknot/rdata_tests_realdata.h
+src/tests/libknot/realdata/libknot/response_tests_realdata.c
+src/tests/libknot/realdata/libknot/response_tests_realdata.h
+src/tests/libknot/realdata/libknot/rrset_tests_realdata.c
+src/tests/libknot/realdata/libknot/rrset_tests_realdata.h
+src/tests/libknot/realdata/libknot/zone_tests_realdata.c
+src/tests/libknot/realdata/libknot/zone_tests_realdata.h
+src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c
+src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h
+src/tests/libknot/realdata/libknot_tests_loader_realdata.c
+src/tests/libknot/realdata/libknot_tests_loader_realdata.h
+src/tests/libknot/libknot/zone_tree_tests.c
+src/tests/libknot/libknot/zone_tree_tests.h
+samples/Makefile.am
+libknot/tsig.h
+libknot/tsig.c
+libknot/tsig-op.c
+libknot/tsig-op.h
diff --git a/Knot.includes b/Knot.includes
new file mode 100644
index 0000000..8184956
--- /dev/null
+++ b/Knot.includes
@@ -0,0 +1,13 @@
+obj
+src/alloc
+src/ctl
+src/dnslib
+src/hash
+src/lib
+src/other
+src/server
+src/stat
+src/tests/libtap
+src/tests
+src/zoneparser
+src \ No newline at end of file
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..30ea215
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,2 @@
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = src samples
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..e52ea78
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,708 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(top_srcdir)/configure AUTHORS COPYING \
+ ChangeLog INSTALL NEWS config.guess config.sub depcomp \
+ install-sh ltmain.sh missing ylwrap
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compiler_flags.m4 \
+ $(top_srcdir)/m4/ax_ext.m4 \
+ $(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/src/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir dist dist-all distcheck
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d "$(distdir)" \
+ || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr "$(distdir)"; }; }
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIMD_FLAGS = @SIMD_FLAGS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = src samples
+all: all-recursive
+
+.SUFFIXES:
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d "$(distdir)" || mkdir "$(distdir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -test -n "$(am__skip_mode_fix)" \
+ || find "$(distdir)" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-lzma: distdir
+ tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+ $(am__remove_distdir)
+
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lzma*) \
+ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @$(am__cd) '$(distuninstallcheck_dir)' \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am am--refresh check check-am clean clean-generic \
+ clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
+ dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
+ distcheck distclean distclean-generic distclean-libtool \
+ distclean-tags distcleancheck distdir distuninstallcheck dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-recursive uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..1496a5e
--- /dev/null
+++ b/README
@@ -0,0 +1,142 @@
+Installation
+============
+
+The following steps should work (verified in VirtualBox only)
+on the distribution/architecture/release combinations as listed bellow.
+
+----------------------------------------------
+Debian (AMD64, I386) 6.0.2.1 (squeeze)
+Ubuntu Server (AMD64, I386) 10.04 LTS
+Ubuntu Desktop (AMD64, I386) 10.04 LTS
+----------------------------------------------
+
+$ # make the system up-to-date
+$
+$ sudo apt-get update
+$ sudo apt-get upgrade
+$
+$ # ensure all prerequisites are installed
+$
+$ sudo apt-get install git-core autoconf libtool flex bison libssl-dev
+$
+$ # the required version of liburcu is not available in the default package sources.
+$
+$ wget http://bd.archive.ubuntu.com/ubuntu/pool/universe/libu/liburcu/liburcu0_0.5.4-1_amd64.deb
+$ wget http://bd.archive.ubuntu.com/ubuntu/pool/universe/libu/liburcu/liburcu-dev_0.5.4-1_amd64.deb
+$ sudo dpkg -i liburcu0_0.5.4-1_amd64.deb
+$ sudo dpkg -i liburcu-dev_0.5.4-1_amd64.deb
+$
+$ # go for the real thing
+$
+$ git clone git://git.nic.cz/knot
+$ cd knot
+$ autoreconf -if
+$ ./configure
+$ make
+$ sudo make install
+$ sudo ldconfig
+
+Alternative packages for I386:
+
+$ # the required version of liburcu is not available in the default package sources.
+$
+$ wget http://bd.archive.ubuntu.com/ubuntu/pool/universe/libu/liburcu/liburcu0_0.5.4-1_i386.deb
+$ wget http://bd.archive.ubuntu.com/ubuntu/pool/universe/libu/liburcu/liburcu-dev_0.5.4-1_i386.deb
+$ sudo dpkg -i liburcu0_0.5.4-1_i386.deb
+$ sudo dpkg -i liburcu-dev_0.5.4-1_i386.deb
+
+Installation on BSD
+===================
+
+Not all prerequisites are available as ports on BSD.
+
+- liburcu must be compiled from sources
+ - version 0.6.4 compiles on BSD without any source code modifications
+ - in case of x86_64 build, CFLAGS nad build type has to be set appropriately.
+ $ CFLAGS=-fPIC ./configure --build amd64
+- flex must be newer version from ports that support reentrant parsers
+
+Knot DNS requires more recent version of flex from ports, to prevent name clash, specify flex destination.
+$ cd <knot sources>
+$ autoreconf -if
+$ ./configure
+$ make && sudo make install
+
+Installation on OS X
+====================
+
+Not all prerequisites are preinstalled for OS X.
+
+- liburcu must be compiled from sources
+ - liburcu requires gcc-4.6 from MacPorts, as it depends on __thread keyword
+ $ CC=gcc-mp-4.6 ARCH=x86_64 ./configure
+ $ make && sudo make install
+
+Compiling Knot DNS with gcc-mp-4.6 is recommended, but not necessary.
+
+Running
+=======
+
+First, each server needs configuration file. Please see samples/knot.sample.conf
+for reference. Minimal configuration can be found in samples/knot.min.conf
+Configuration zone has to specify:
+* storage for PID files, compiled zones etc.
+* network interfaces
+* served zones
+
+$ cp samples/knot.min.conf myserver.conf
+$ vim myserver.conf # or your favourite text editor
+
+Second, zone files have to be compiled to binary form in order for server to
+load them. Binary 'knotc' (controller) offers functionality for everything from zone file
+management to controlling server instance. Most important parameter is '-c' that
+specifies config file for our server. Compiled zones are saved to storage
+defined in 'storage' variable in configuration.
+
+$ knotc -h # see what it can do
+$ knotc -c myserver.conf compile # compile zone files to binary format
+
+Third, lets load server. You can do this by running 'knotd' directly, or with
+'knotc' as well. Server is able to run in daemonized or interactive mode.
+Lets start our server in interactive mode (parameter '-i') to see if it runs.
+
+$ knotc -c myserver.conf -i start # start server in interactive mode
+
+Running as daemon
+=================
+
+Controller runs server in daemonized mode as default. Disadvantage is, that
+it closes stdout/stderr so you need to set up either syslog or logging to
+own files in the configuration. Controller parameter '-w' waits for the operation
+to finish. Let's test server functionality.
+
+$ knotc -c myserver.conf -w start # start server
+$ dig @$ADDR -p $PORT example.com # issue a query and see result
+$ ...
+$ knotc -c myserver.conf -w stop # stop server
+
+Also, keep in mind that zone files have to be compiled before they are loaded
+to server. Workflow is as follows:
+
+$ knotc -c myserver.conf -w start
+$ <edit zonefile>
+$ knotc -c myserver.conf compile # compile zones to binary format
+$ knotc -c myserver.conf reload # reconfigures server on-the-fly
+$ dig @$ADDR -p $PORT example.com # issue a query and see result
+$ ...
+$ knotc -c myserver.conf stop
+
+Supported features
+==================
+
+DNS functions:
+* AXFR (master)
+* EDNS0
+* DNSSEC
+* NSEC3
+
+Server features:
+* Adding/removing zones on-the-fly
+* Reconfiguring server instance on-the-fly
+* IPv6 support
+* Semantic checks of loaded zone
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..2b546eb
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,1020 @@
+# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],,
+[m4_warning([this file was generated for autoconf 2.67.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.11'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.11.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.11.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 10
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 16
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.62])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES(OBJC)],
+ [define([AC_PROG_OBJC],
+ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_PROG_LEX
+# -----------
+# Autoconf leaves LEX=: if lex or flex can't be found. Change that to a
+# "missing" invocation, for better error output.
+AC_DEFUN([AM_PROG_LEX],
+[AC_PREREQ(2.50)dnl
+AC_REQUIRE([AM_MISSING_HAS_RUN])dnl
+AC_REQUIRE([AC_PROG_LEX])dnl
+if test "$LEX" = :; then
+ LEX=${am_missing_run}flex
+fi])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless `enable' is passed literally.
+# For symmetry, `disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+ [[\\/$]]* | ?:[[\\/]]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/ax_check_compiler_flags.m4])
+m4_include([m4/ax_ext.m4])
+m4_include([m4/ax_gcc_x86_cpuid.m4])
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
diff --git a/config.guess b/config.guess
new file mode 100755
index 0000000..c2246a4
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1502 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+# Free Software Foundation, Inc.
+
+timestamp='2009-12-30'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[456])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.sub b/config.sub
new file mode 100755
index 0000000..c2d1257
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1714 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+# Free Software Foundation, Inc.
+
+timestamp='2010-01-22'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile-* | tilegx-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ # This must be matched before tile*.
+ tilegx*)
+ basic_machine=tilegx-unknown
+ os=-linux-gnu
+ ;;
+ tile*)
+ basic_machine=tile-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755
index 0000000..5ee05a9
--- /dev/null
+++ b/configure
@@ -0,0 +1,15763 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.67 for knot 0.8.
+#
+# Report bugs to <knot-dns@labs.nic.cz>.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: knot-dns@labs.nic.cz about your system, including any
+$0: error possibly output before this message. Then install
+$0: a modern shell, or manually run the script under such a
+$0: shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$lt_ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','`
+ ;;
+esac
+
+ECHO=${lt_ECHO-echo}
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
+ # Yippee, $ECHO works!
+ :
+else
+ # Restart under the correct shell.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<_LT_EOF
+$*
+_LT_EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$lt_ECHO"; then
+ if test "X${echo_test_string+set}" != Xset; then
+ # find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
+ { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
+ then
+ break
+ fi
+ done
+ fi
+
+ if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+ else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ ECHO="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$ECHO" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ ECHO='print -r'
+ elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
+ else
+ # Try using printf.
+ ECHO='printf %s\n'
+ if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ ECHO="$CONFIG_SHELL $0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ ECHO="$CONFIG_SHELL $0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+ if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "$0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ ECHO=echo
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+lt_ECHO=$ECHO
+if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+ lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
+fi
+
+
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='knot'
+PACKAGE_TARNAME='knot'
+PACKAGE_VERSION='0.8'
+PACKAGE_STRING='knot 0.8'
+PACKAGE_BUGREPORT='knot-dns@labs.nic.cz'
+PACKAGE_URL=''
+
+ac_unique_file="src/knot/main.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_header_list=
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+YFLAGS
+YACC
+LEXLIB
+LEX_OUTPUT_ROOT
+LEX
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+lt_ECHO
+RANLIB
+AR
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+SIMD_FLAGS
+EGREP
+GREP
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_dependency_tracking
+enable_maintainer_mode
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+enable_libtool_lock
+enable_ldns
+enable_debug
+enable_recvmmsg
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+YACC
+YFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used" >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures knot 0.8 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/knot]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of knot 0.8:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --disable-maintainer-mode disable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-static[=PKGS] build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --enable-ldns=yes|no Enable tests with ldns [default=no]
+ --enable-debug=brief|verbose|details
+ enable given debug level [default=disabled]
+ --enable-recvmmsg=yes|no
+ enable recvmmsg() network API under Linux (kernel
+ support required) (set to 'no' if you have trouble
+ running server under valgrind) [default=yes]
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-pic try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ YACC The `Yet Another C Compiler' implementation to use. Defaults to
+ the first program found out of: `bison -y', `byacc', `yacc'.
+ YFLAGS The list of arguments that will be passed by default to $YACC.
+ This script will default YFLAGS to the empty string to avoid a
+ default value of `-d' given by some make applications.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <knot-dns@labs.nic.cz>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+knot configure 0.8
+generated by GNU Autoconf 2.67
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval "test \"\${$3+set}\"" = set; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ----------------------------------- ##
+## Report this to knot-dns@labs.nic.cz ##
+## ----------------------------------- ##"
+ ) | sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_find_intX_t LINENO BITS VAR
+# -----------------------------------
+# Finds a signed integer type with width BITS, setting cache variable VAR
+# accordingly.
+ac_fn_c_find_intX_t ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5
+$as_echo_n "checking for int$2_t... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ # Order is important - never check a type that is potentially smaller
+ # than half of the expected target width.
+ for ac_type in int$2_t 'int' 'long int' \
+ 'long long int' 'short int' 'signed char'; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+ enum { N = $2 / 2 - 1 };
+int
+main ()
+{
+static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+ enum { N = $2 / 2 - 1 };
+int
+main ()
+{
+static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1)
+ < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ case $ac_type in #(
+ int$2_t) :
+ eval "$3=yes" ;; #(
+ *) :
+ eval "$3=\$ac_type" ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if eval test \"x\$"$3"\" = x"no"; then :
+
+else
+ break
+fi
+ done
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_find_intX_t
+
+# ac_fn_c_find_uintX_t LINENO BITS VAR
+# ------------------------------------
+# Finds an unsigned integer type with width BITS, setting cache variable VAR
+# accordingly.
+ac_fn_c_find_uintX_t ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5
+$as_echo_n "checking for uint$2_t... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ # Order is important - never check a type that is potentially smaller
+ # than half of the expected target width.
+ for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \
+ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ case $ac_type in #(
+ uint$2_t) :
+ eval "$3=yes" ;; #(
+ *) :
+ eval "$3=\$ac_type" ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if eval test \"x\$"$3"\" = x"no"; then :
+
+else
+ break
+fi
+ done
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_find_uintX_t
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by knot $as_me 0.8, which was
+generated by GNU Autoconf 2.67. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5 ; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+as_fn_append ac_header_list " stdlib.h"
+as_fn_append ac_header_list " unistd.h"
+as_fn_append ac_header_list " sys/param.h"
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+am__api_version='1.11'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5 ;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5 ;;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if test "${ac_cv_path_mkdir+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+ [\\/$]* | ?:[\\/]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='knot'
+ VERSION='0.8'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers src/config.h"
+
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5 ; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5 ; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5 ; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5 ; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5 ; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5 ; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = x""yes; then :
+ MINIX=yes
+else
+ MINIX=
+fi
+
+
+ if test "$MINIX" = yes; then
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+
+$as_echo "#define _MINIX 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if test "${ac_cv_safe_to_define___extensions__+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# define __EXTENSIONS__ 1
+ $ac_includes_default
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_safe_to_define___extensions__=yes
+else
+ ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+ $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+ $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid output" >&5
+$as_echo_n "checking for x86 cpuid output... " >&6; }
+if test "${ax_cv_gcc_x86_cpuid_+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ax_cv_gcc_x86_cpuid_=unknown
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+
+ int op = , eax, ebx, ecx, edx;
+ FILE *f;
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
+ __asm__("push %%rbx\n\t"
+ "cpuid\n\t"
+ "pop %%rbx"
+ : "=a" (eax), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ __asm__("push %%rbx\n\t"
+ "cpuid\n\t"
+ "mov %%rbx, %%rax\n\t"
+ "pop %%rbx"
+ : "=a" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+#else
+ __asm__("push %%ebx\n\t"
+ "cpuid\n\t"
+ "pop %%ebx"
+ : "=a" (eax), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ __asm__("push %%ebx\n\t"
+ "cpuid\n\t"
+ "mov %%ebx, %%eax\n\t"
+ "pop %%ebx"
+ : "=a" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+#endif
+ f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+ fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+ fclose(f);
+ return 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ax_cv_gcc_x86_cpuid_=`cat conftest_cpuid`; rm -f conftest_cpuid
+else
+ ax_cv_gcc_x86_cpuid_=unknown; rm -f conftest_cpuid
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_" >&5
+$as_echo "$ax_cv_gcc_x86_cpuid_" >&6; }
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86 cpuid 0x00000001 output" >&5
+$as_echo_n "checking for x86 cpuid 0x00000001 output... " >&6; }
+if test "${ax_cv_gcc_x86_cpuid_0x00000001+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ax_cv_gcc_x86_cpuid_0x00000001=unknown
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+
+ int op = 0x00000001, eax, ebx, ecx, edx;
+ FILE *f;
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
+ __asm__("push %%rbx\n\t"
+ "cpuid\n\t"
+ "pop %%rbx"
+ : "=a" (eax), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ __asm__("push %%rbx\n\t"
+ "cpuid\n\t"
+ "mov %%rbx, %%rax\n\t"
+ "pop %%rbx"
+ : "=a" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+#else
+ __asm__("push %%ebx\n\t"
+ "cpuid\n\t"
+ "pop %%ebx"
+ : "=a" (eax), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ __asm__("push %%ebx\n\t"
+ "cpuid\n\t"
+ "mov %%ebx, %%eax\n\t"
+ "pop %%ebx"
+ : "=a" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+#endif
+ f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+ fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+ fclose(f);
+ return 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ax_cv_gcc_x86_cpuid_0x00000001=`cat conftest_cpuid`; rm -f conftest_cpuid
+else
+ ax_cv_gcc_x86_cpuid_0x00000001=unknown; rm -f conftest_cpuid
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_gcc_x86_cpuid_0x00000001" >&5
+$as_echo "$ax_cv_gcc_x86_cpuid_0x00000001" >&6; }
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ ecx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 3`
+ edx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 4`
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mmx is supported" >&5
+$as_echo_n "checking whether mmx is supported... " >&6; }
+if test "${ax_cv_have_mmx_ext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_cv_have_mmx_ext=no
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ if test "$((0x$edx>>23&0x01))" = 1; then
+ ax_cv_have_mmx_ext=yes
+ fi
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_mmx_ext" >&5
+$as_echo "$ax_cv_have_mmx_ext" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sse is supported" >&5
+$as_echo_n "checking whether sse is supported... " >&6; }
+if test "${ax_cv_have_sse_ext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_cv_have_sse_ext=no
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ if test "$((0x$edx>>25&0x01))" = 1; then
+ ax_cv_have_sse_ext=yes
+ fi
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_sse_ext" >&5
+$as_echo "$ax_cv_have_sse_ext" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sse2 is supported" >&5
+$as_echo_n "checking whether sse2 is supported... " >&6; }
+if test "${ax_cv_have_sse2_ext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_cv_have_sse2_ext=no
+ if test "$((0x$edx>>26&0x01))" = 1; then
+ ax_cv_have_sse2_ext=yes
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_sse2_ext" >&5
+$as_echo "$ax_cv_have_sse2_ext" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sse3 is supported" >&5
+$as_echo_n "checking whether sse3 is supported... " >&6; }
+if test "${ax_cv_have_sse3_ext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_cv_have_sse3_ext=no
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ if test "$((0x$ecx&0x01))" = 1; then
+ ax_cv_have_sse3_ext=yes
+ fi
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_sse3_ext" >&5
+$as_echo "$ax_cv_have_sse3_ext" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ssse3 is supported" >&5
+$as_echo_n "checking whether ssse3 is supported... " >&6; }
+if test "${ax_cv_have_ssse3_ext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_cv_have_ssse3_ext=no
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ if test "$((0x$ecx>>9&0x01))" = 1; then
+ ax_cv_have_ssse3_ext=yes
+ fi
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have_ssse3_ext" >&5
+$as_echo "$ax_cv_have_ssse3_ext" >&6; }
+
+ if test "$ax_cv_have_mmx_ext" = yes; then
+
+$as_echo "#define HAVE_MMX /**/" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -mmmx" >&5
+$as_echo_n "checking whether C compiler accepts -mmmx... " >&6; }
+if test "${ax_cv_c_flags__mmmx+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_save_FLAGS=$CFLAGS
+ CFLAGS="-mmmx"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ax_cv_c_flags__mmmx=yes
+else
+ ax_cv_c_flags__mmmx=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_save_FLAGS
+fi
+
+eval ax_check_compiler_flags=$ax_cv_c_flags__mmmx
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+ SIMD_FLAGS="$SIMD_FLAGS -mmmx"
+else
+ :
+fi
+
+ fi
+
+ if test "$ax_cv_have_sse_ext" = yes; then
+
+$as_echo "#define HAVE_SSE /**/" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse" >&5
+$as_echo_n "checking whether C compiler accepts -msse... " >&6; }
+if test "${ax_cv_c_flags__msse+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_save_FLAGS=$CFLAGS
+ CFLAGS="-msse"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ax_cv_c_flags__msse=yes
+else
+ ax_cv_c_flags__msse=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_save_FLAGS
+fi
+
+eval ax_check_compiler_flags=$ax_cv_c_flags__msse
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+ SIMD_FLAGS="$SIMD_FLAGS -msse"
+else
+ :
+fi
+
+ fi
+
+ if test "$ax_cv_have_sse2_ext" = yes; then
+
+$as_echo "#define HAVE_SSE2 /**/" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse2" >&5
+$as_echo_n "checking whether C compiler accepts -msse2... " >&6; }
+if test "${ax_cv_c_flags__msse2+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_save_FLAGS=$CFLAGS
+ CFLAGS="-msse2"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ax_cv_c_flags__msse2=yes
+else
+ ax_cv_c_flags__msse2=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_save_FLAGS
+fi
+
+eval ax_check_compiler_flags=$ax_cv_c_flags__msse2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+ SIMD_FLAGS="$SIMD_FLAGS -msse2"
+else
+ :
+fi
+
+ fi
+
+ if test "$ax_cv_have_sse3_ext" = yes; then
+
+$as_echo "#define HAVE_SSE3 /**/" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -msse3" >&5
+$as_echo_n "checking whether C compiler accepts -msse3... " >&6; }
+if test "${ax_cv_c_flags__msse3+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_save_FLAGS=$CFLAGS
+ CFLAGS="-msse3"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ax_cv_c_flags__msse3=yes
+else
+ ax_cv_c_flags__msse3=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_save_FLAGS
+fi
+
+eval ax_check_compiler_flags=$ax_cv_c_flags__msse3
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5
+$as_echo "$ax_check_compiler_flags" >&6; }
+if test "x$ax_check_compiler_flags" = xyes; then
+ SIMD_FLAGS="$SIMD_FLAGS -msse3"
+else
+ :
+fi
+
+ fi
+
+ if test "$ax_cv_have_ssse3_ext" = yes; then
+
+$as_echo "#define HAVE_SSSE3 /**/" >>confdefs.h
+
+ fi
+
+
+
+
+# Enable maintainer mode by default for development
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to disable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to disable maintainer-specific portions of Makefiles... " >&6; }
+ # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=yes
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+ if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+# Initialize libtool
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.2.6b'
+macro_revision='1.3017'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if test "${ac_cv_path_SED+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if test "${ac_cv_path_FGREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if test "${lt_cv_path_NM+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in "dumpbin -symbols" "link -dump -symbols"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DUMPBIN+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in "dumpbin -symbols" "link -dump -symbols"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if test "${lt_cv_nm_interface+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:5468: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:5471: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:5474: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
+ = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if test "${lt_cv_ld_reload_flag+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJDUMP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if test "${lt_cv_deplibs_check_method+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AR+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_AR="ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5
+ (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line 6679 "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if test "${lt_cv_cc_needs_belf+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DSYMUTIL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_NMEDIT+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_LIPO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL64+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if test "${lt_cv_apple_cc_single_mod+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if test "${lt_cv_ld_exported_symbols_list+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[012]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+# Set options
+
+
+
+ enable_dlopen=no
+
+
+ enable_win32_dll=no
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+ # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; pic_mode="$withval"
+else
+ pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if test "${lt_cv_objdir+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:7941: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:7945: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl*)
+ # IBM XL C 8.0/Fortran 10.1 on PPC
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ *Sun\ F*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5
+$as_echo "$lt_prog_compiler_pic" >&6; }
+
+
+
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:8280: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:8284: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test "${lt_cv_prog_compiler_static_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:8385: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:8389: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:8440: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:8444: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu)
+ link_all_deplibs=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld='-rpath $libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ link_all_deplibs=no
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ whole_archive_flag_spec=''
+ link_all_deplibs=yes
+ allow_undefined_flag="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=echo
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld='+b $libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo(void) {}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ archive_cmds_need_lc=no
+ else
+ archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5
+$as_echo "$archive_cmds_need_lc" >&6; }
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # Some binutils ld are patched to set DT_RUNPATH
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+ test "$inherit_rpath" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = x""yes; then :
+ lt_cv_dlopen="shl_load"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = x""yes; then :
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = x""yes; then :
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line 10824 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self_static+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line 10920 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report which library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+# Checks for programs.
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5 ; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for reentrant lex" >&5
+$as_echo_n "checking for reentrant lex... " >&6; }
+if test "${ac_cv_path_LEX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LEX"; then
+ ac_path_LEX_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in $LEX flex gflex; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_LEX="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_LEX" && $as_test_x "$ac_path_LEX"; } || continue
+cat >conftest.l <<_ACEOF
+%{
+%}
+
+%option reentrant
+%option bison-bridge
+%option noinput
+%option nounput
+%option noreject
+
+BLANK \t\n
+
+%%
+<<EOF>> return 0;
+%%
+_ACEOF
+{ { ac_try="$ac_path_LEX conftest.l"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_path_LEX conftest.l") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+test $ac_status -eq 0 && ac_cv_path_LEX=$ac_path_LEX ac_path_LEX_found=true
+rm -f conftest.l lexyy.c lex.yy.c
+
+ $ac_path_LEX_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_LEX"; then
+ as_fn_error $? "could not find lex that supports reentrant parsers" "$LINENO" 5
+ fi
+else
+ ac_cv_path_LEX=$LEX
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_LEX" >&5
+$as_echo "$ac_cv_path_LEX" >&6; }
+LEX=$ac_cv_path_LEX
+
+for ac_prog in flex lex
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_LEX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LEX"; then
+ ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_LEX="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5
+$as_echo "$LEX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+ cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { yyless (input () != 0); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+ return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ { ac_try="$LEX conftest.l"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$LEX conftest.l") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5
+$as_echo_n "checking lex output file root... " >&6; }
+if test "${ac_cv_prog_lex_root+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+if test -f lex.yy.c; then
+ ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+ ac_cv_prog_lex_root=lexyy
+else
+ as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5
+$as_echo "$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5
+$as_echo_n "checking lex library... " >&6; }
+if test "${ac_cv_lib_lex+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_save_LIBS=$LIBS
+ ac_cv_lib_lex='none needed'
+ for ac_lib in '' -lfl -ll; do
+ LIBS="$ac_lib $ac_save_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_lex=$ac_lib
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ test "$ac_cv_lib_lex" != 'none needed' && break
+ done
+ LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5
+$as_echo "$ac_cv_lib_lex" >&6; }
+ test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5
+$as_echo_n "checking whether yytext is a pointer... " >&6; }
+if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent. Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_prog_lex_yytext_pointer=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5
+$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+if test "$LEX" = :; then
+ LEX=${am_missing_run}flex
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_YACC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_YACC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
+$as_echo "$YACC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+YACC_BISON=`bison --version | awk '{print $1;exit}'`
+if test "$YACC_BISON" != "bison"; then
+ as_fn_error $? "GNU bison needed for reentrant parsers, set the \$YACC variable before running configure" "$LINENO" 5
+fi
+
+
+# Set compiler compatibility flags
+ac_c_preproc_warn_flag=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if test "${ac_cv_prog_cc_c99+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+}
+
+int
+main ()
+{
+
+ // Check bool.
+ _Bool success = false;
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
+
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+
+fi
+
+
+
+# Check whether --enable-ldns was given.
+if test "${enable_ldns+set}" = set; then :
+ enableval=$enable_ldns; case "${enableval}" in
+ yes) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ldns_rr_list_pop_rrset" >&5
+$as_echo_n "checking for library containing ldns_rr_list_pop_rrset... " >&6; }
+if test "${ac_cv_search_ldns_rr_list_pop_rrset+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ldns_rr_list_pop_rrset ();
+int
+main ()
+{
+return ldns_rr_list_pop_rrset ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' ldns; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_ldns_rr_list_pop_rrset=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_ldns_rr_list_pop_rrset+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_ldns_rr_list_pop_rrset+set}" = set; then :
+
+else
+ ac_cv_search_ldns_rr_list_pop_rrset=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ldns_rr_list_pop_rrset" >&5
+$as_echo "$ac_cv_search_ldns_rr_list_pop_rrset" >&6; }
+ac_res=$ac_cv_search_ldns_rr_list_pop_rrset
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+$as_echo "#define HAVE_LDNS 1" >>confdefs.h
+
+else
+ as_fn_error $? "ldns not found" "$LINENO" 5
+fi
+ ;;
+ no) ldns=false ;;
+ *) as_fn_error $? "bad value ${enableval} for --enable-ldns" "$LINENO" 5 ;;
+ esac
+else
+ ldns=false
+fi
+
+
+# Debug level
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+ enableval=$enable_debug; # Not all shells support fall-through with ;& so I have to duplicate
+ case "x${enableval}" in
+ xdetails)
+
+$as_echo "#define DEBUG_ENABLE_DETAILS 1" >>confdefs.h
+
+
+$as_echo "#define DEBUG_ENABLE_VERBOSE 1" >>confdefs.h
+
+
+$as_echo "#define DEBUG_ENABLE_BRIEF 1" >>confdefs.h
+
+ ;;
+ xverbose)
+
+$as_echo "#define DEBUG_ENABLE_VERBOSE 1" >>confdefs.h
+
+
+$as_echo "#define DEBUG_ENABLE_BRIEF 1" >>confdefs.h
+
+ ;;
+ xbrief)
+
+$as_echo "#define DEBUG_ENABLE_BRIEF 1" >>confdefs.h
+
+ ;;
+ esac
+fi
+
+
+# recvmmsg() (valgrind doesn't support it, so disable for debugging)
+# Check whether --enable-recvmmsg was given.
+if test "${enable_recvmmsg+set}" = set; then :
+ enableval=$enable_recvmmsg; case "${enableval}" in
+ yes)
+
+$as_echo "#define ENABLE_RECVMMSG 1" >>confdefs.h
+
+ ;;
+ no)
+ recvmmsg=false
+ ;;
+ *)
+ as_fn_error $? "bad value ${enableval} for --enable-recvmmsg" "$LINENO" 5
+ ;;
+ esac
+else
+
+
+$as_echo "#define ENABLE_RECVMMSG 1" >>confdefs.h
+
+ recvmmsg=true
+
+fi
+
+
+# Checks for libraries.
+# FIXME: Replace `main' with a function in `-lm':
+# TODO: check if paths exist before appending
+CFLAGS="$CFLAGS -I/usr/local/include"
+LDFLAGS="$LDFLAGS -L/usr/local/lib"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pow" >&5
+$as_echo_n "checking for library containing pow... " >&6; }
+if test "${ac_cv_search_pow+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pow ();
+int
+main ()
+{
+return pow ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' m; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_pow=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_pow+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_pow+set}" = set; then :
+
+else
+ ac_cv_search_pow=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pow" >&5
+$as_echo "$ac_cv_search_pow" >&6; }
+ac_res=$ac_cv_search_pow
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5
+$as_echo_n "checking for library containing pthread_create... " >&6; }
+if test "${ac_cv_search_pthread_create+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' pthread; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_pthread_create=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_pthread_create+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_pthread_create+set}" = set; then :
+
+else
+ ac_cv_search_pthread_create=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5
+$as_echo "$ac_cv_search_pthread_create" >&6; }
+ac_res=$ac_cv_search_pthread_create
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else
+ as_fn_error $? "pthreads not found" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing rcu_set_pointer_sym" >&5
+$as_echo_n "checking for library containing rcu_set_pointer_sym... " >&6; }
+if test "${ac_cv_search_rcu_set_pointer_sym+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char rcu_set_pointer_sym ();
+int
+main ()
+{
+return rcu_set_pointer_sym ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' urcu; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_rcu_set_pointer_sym=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_rcu_set_pointer_sym+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_rcu_set_pointer_sym+set}" = set; then :
+
+else
+ ac_cv_search_rcu_set_pointer_sym=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rcu_set_pointer_sym" >&5
+$as_echo "$ac_cv_search_rcu_set_pointer_sym" >&6; }
+ac_res=$ac_cv_search_rcu_set_pointer_sym
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else
+ as_fn_error $? "liburcu not found" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
+$as_echo_n "checking for library containing dlopen... " >&6; }
+if test "${ac_cv_search_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' dl; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_dlopen=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_dlopen+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_dlopen+set}" = set; then :
+
+else
+ ac_cv_search_dlopen=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
+$as_echo "$ac_cv_search_dlopen" >&6; }
+ac_res=$ac_cv_search_dlopen
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+#AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([librt not found])])
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing OpenSSL_add_all_digests" >&5
+$as_echo_n "checking for library containing OpenSSL_add_all_digests... " >&6; }
+if test "${ac_cv_search_OpenSSL_add_all_digests+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char OpenSSL_add_all_digests ();
+int
+main ()
+{
+return OpenSSL_add_all_digests ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' crypto; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_OpenSSL_add_all_digests=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_OpenSSL_add_all_digests+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_OpenSSL_add_all_digests+set}" = set; then :
+
+else
+ ac_cv_search_OpenSSL_add_all_digests=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_OpenSSL_add_all_digests" >&5
+$as_echo "$ac_cv_search_OpenSSL_add_all_digests" >&6; }
+ac_res=$ac_cv_search_OpenSSL_add_all_digests
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else
+ as_fn_error $? "libcrypto not found" "$LINENO" 5
+fi
+
+#AC_SEARCH_LIBS([ldns_rr_list_pop_rrset], [ldns], [], [AC_MSG_ERROR([libldns not found])])
+
+# Checks for header files.
+for ac_header in sys/types.h netinet/in.h arpa/nameser.h netdb.h resolv.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h> /* inet_ functions / structs */
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h> /* DNS HEADER struct */
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stdint.h stdlib.h string.h strings.h sys/socket.h sys/time.h syslog.h unistd.h urcu.h ev.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# Checks for typedefs, structures, and compiler characteristics.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5
+$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; }
+if test "${ac_cv_header_stdbool_h+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdbool.h>
+#ifndef bool
+ "error: bool is not defined"
+#endif
+#ifndef false
+ "error: false is not defined"
+#endif
+#if false
+ "error: false is not 0"
+#endif
+#ifndef true
+ "error: true is not defined"
+#endif
+#if true != 1
+ "error: true is not 1"
+#endif
+#ifndef __bool_true_false_are_defined
+ "error: __bool_true_false_are_defined is not defined"
+#endif
+
+ struct s { _Bool s: 1; _Bool t; } s;
+
+ char a[true == 1 ? 1 : -1];
+ char b[false == 0 ? 1 : -1];
+ char c[__bool_true_false_are_defined == 1 ? 1 : -1];
+ char d[(bool) 0.5 == true ? 1 : -1];
+ bool e = &s;
+ char f[(_Bool) 0.0 == false ? 1 : -1];
+ char g[true];
+ char h[sizeof (_Bool)];
+ char i[sizeof s.t];
+ enum { j = false, k = true, l = false * true, m = true * 256 };
+ /* The following fails for
+ HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */
+ _Bool n[m];
+ char o[sizeof n == m * sizeof n[0] ? 1 : -1];
+ char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];
+# if defined __xlc__ || defined __GNUC__
+ /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0
+ reported by James Lemley on 2005-10-05; see
+ http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html
+ This test is not quite right, since xlc is allowed to
+ reject this program, as the initializer for xlcbug is
+ not one of the forms that C requires support for.
+ However, doing the test right would require a runtime
+ test, and that would make cross-compilation harder.
+ Let us hope that IBM fixes the xlc bug, and also adds
+ support for this kind of constant expression. In the
+ meantime, this test will reject xlc, which is OK, since
+ our stdbool.h substitute should suffice. We also test
+ this with GCC, where it should work, to detect more
+ quickly whether someone messes up the test in the
+ future. */
+ char digs[] = "0123456789";
+ int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1);
+# endif
+ /* Catch a bug in an HP-UX C compiler. See
+ http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html
+ http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html
+ */
+ _Bool q = true;
+ _Bool *pq = &q;
+
+int
+main ()
+{
+
+ *pq |= q;
+ *pq |= ! q;
+ /* Refer to every declared value, to avoid compiler optimizations. */
+ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l
+ + !m + !n + !o + !p + !q + !pq);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdbool_h=yes
+else
+ ac_cv_header_stdbool_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5
+$as_echo "$ac_cv_header_stdbool_h" >&6; }
+ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default"
+if test "x$ac_cv_type__Bool" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE__BOOL 1
+_ACEOF
+
+
+fi
+
+if test $ac_cv_header_stdbool_h = yes; then
+
+$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if test "${ac_cv_c_inline+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t"
+case $ac_cv_c_int64_t in #(
+ no|yes) ;; #(
+ *)
+
+cat >>confdefs.h <<_ACEOF
+#define int64_t $ac_cv_c_int64_t
+_ACEOF
+;;
+esac
+
+ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
+if test "x$ac_cv_type_pid_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define pid_t int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default"
+if test "x$ac_cv_type_ssize_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define ssize_t int
+_ACEOF
+
+fi
+
+ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t"
+case $ac_cv_c_uint16_t in #(
+ no|yes) ;; #(
+ *)
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint16_t $ac_cv_c_uint16_t
+_ACEOF
+;;
+ esac
+
+ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t"
+case $ac_cv_c_uint32_t in #(
+ no|yes) ;; #(
+ *)
+
+$as_echo "#define _UINT32_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t $ac_cv_c_uint32_t
+_ACEOF
+;;
+ esac
+
+ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t"
+case $ac_cv_c_uint64_t in #(
+ no|yes) ;; #(
+ *)
+
+$as_echo "#define _UINT64_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint64_t $ac_cv_c_uint64_t
+_ACEOF
+;;
+ esac
+
+ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t"
+case $ac_cv_c_uint8_t in #(
+ no|yes) ;; #(
+ *)
+
+$as_echo "#define _UINT8_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint8_t $ac_cv_c_uint8_t
+_ACEOF
+;;
+ esac
+
+
+# Checks for library functions.
+for ac_header in vfork.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default"
+if test "x$ac_cv_header_vfork_h" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_VFORK_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in fork vfork
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+if test "x$ac_cv_func_fork" = xyes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5
+$as_echo_n "checking for working fork... " >&6; }
+if test "${ac_cv_func_fork_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ac_cv_func_fork_works=cross
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ /* By Ruediger Kuhlmann. */
+ return fork () < 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_func_fork_works=yes
+else
+ ac_cv_func_fork_works=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5
+$as_echo "$ac_cv_func_fork_works" >&6; }
+
+else
+ ac_cv_func_fork_works=$ac_cv_func_fork
+fi
+if test "x$ac_cv_func_fork_works" = xcross; then
+ case $host in
+ *-*-amigaos* | *-*-msdosdjgpp*)
+ # Override, as these systems have only a dummy fork() stub
+ ac_cv_func_fork_works=no
+ ;;
+ *)
+ ac_cv_func_fork_works=yes
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5
+$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;}
+fi
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+if test "x$ac_cv_func_vfork" = xyes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5
+$as_echo_n "checking for working vfork... " >&6; }
+if test "${ac_cv_func_vfork_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ac_cv_func_vfork_works=cross
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Thanks to Paul Eggert for this test. */
+$ac_includes_default
+#include <sys/wait.h>
+#ifdef HAVE_VFORK_H
+# include <vfork.h>
+#endif
+/* On some sparc systems, changes by the child to local and incoming
+ argument registers are propagated back to the parent. The compiler
+ is told about this with #include <vfork.h>, but some compilers
+ (e.g. gcc -O) don't grok <vfork.h>. Test for this by using a
+ static variable whose address is put into a register that is
+ clobbered by the vfork. */
+static void
+#ifdef __cplusplus
+sparc_address_test (int arg)
+# else
+sparc_address_test (arg) int arg;
+#endif
+{
+ static pid_t child;
+ if (!child) {
+ child = vfork ();
+ if (child < 0) {
+ perror ("vfork");
+ _exit(2);
+ }
+ if (!child) {
+ arg = getpid();
+ write(-1, "", 0);
+ _exit (arg);
+ }
+ }
+}
+
+int
+main ()
+{
+ pid_t parent = getpid ();
+ pid_t child;
+
+ sparc_address_test (0);
+
+ child = vfork ();
+
+ if (child == 0) {
+ /* Here is another test for sparc vfork register problems. This
+ test uses lots of local variables, at least as many local
+ variables as main has allocated so far including compiler
+ temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris
+ 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should
+ reuse the register of parent for one of the local variables,
+ since it will think that parent can't possibly be used any more
+ in this routine. Assigning to the local variable will thus
+ munge parent in the parent process. */
+ pid_t
+ p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
+ p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
+ /* Convince the compiler that p..p7 are live; otherwise, it might
+ use the same hardware register for all 8 local variables. */
+ if (p != p1 || p != p2 || p != p3 || p != p4
+ || p != p5 || p != p6 || p != p7)
+ _exit(1);
+
+ /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent
+ from child file descriptors. If the child closes a descriptor
+ before it execs or exits, this munges the parent's descriptor
+ as well. Test for this by closing stdout in the child. */
+ _exit(close(fileno(stdout)) != 0);
+ } else {
+ int status;
+ struct stat st;
+
+ while (wait(&status) != child)
+ ;
+ return (
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+
+ /* Did the vfork/compiler bug occur? */
+ || parent != getpid()
+
+ /* Did the file descriptor bug occur? */
+ || fstat(fileno(stdout), &st) != 0
+ );
+ }
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_func_vfork_works=yes
+else
+ ac_cv_func_vfork_works=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5
+$as_echo "$ac_cv_func_vfork_works" >&6; }
+
+fi;
+if test "x$ac_cv_func_fork_works" = xcross; then
+ ac_cv_func_vfork_works=$ac_cv_func_vfork
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5
+$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;}
+fi
+
+if test "x$ac_cv_func_vfork_works" = xyes; then
+
+$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h
+
+else
+
+$as_echo "#define vfork fork" >>confdefs.h
+
+fi
+if test "x$ac_cv_func_fork_works" = xyes; then
+
+$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h
+
+fi
+
+
+
+
+ for ac_header in $ac_header_list
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+for ac_func in getpagesize
+do :
+ ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
+if test "x$ac_cv_func_getpagesize" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETPAGESIZE 1
+_ACEOF
+
+fi
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5
+$as_echo_n "checking for working mmap... " >&6; }
+if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ac_cv_func_mmap_fixed_mapped=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+/* malloc might have been renamed as rpl_malloc. */
+#undef malloc
+
+/* Thanks to Mike Haertel and Jim Avera for this test.
+ Here is a matrix of mmap possibilities:
+ mmap private not fixed
+ mmap private fixed at somewhere currently unmapped
+ mmap private fixed at somewhere already mapped
+ mmap shared not fixed
+ mmap shared fixed at somewhere currently unmapped
+ mmap shared fixed at somewhere already mapped
+ For private mappings, we should verify that changes cannot be read()
+ back from the file, nor mmap's back from the file at a different
+ address. (There have been systems where private was not correctly
+ implemented like the infamous i386 svr4.0, and systems where the
+ VM page cache was not coherent with the file system buffer cache
+ like early versions of FreeBSD and possibly contemporary NetBSD.)
+ For shared mappings, we should conversely verify that changes get
+ propagated back to all the places they're supposed to be.
+
+ Grep wants private fixed already mapped.
+ The main things grep needs to know about mmap are:
+ * does it exist and is it safe to write into the mmap'd area
+ * how to use it (BSD variants) */
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H
+char *malloc ();
+#endif
+
+/* This mess was copied from the GNU getpagesize.h. */
+#ifndef HAVE_GETPAGESIZE
+# ifdef _SC_PAGESIZE
+# define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+# ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define getpagesize() EXEC_PAGESIZE
+# else /* no EXEC_PAGESIZE */
+# ifdef NBPG
+# define getpagesize() NBPG * CLSIZE
+# ifndef CLSIZE
+# define CLSIZE 1
+# endif /* no CLSIZE */
+# else /* no NBPG */
+# ifdef NBPC
+# define getpagesize() NBPC
+# else /* no NBPC */
+# ifdef PAGESIZE
+# define getpagesize() PAGESIZE
+# endif /* PAGESIZE */
+# endif /* no NBPC */
+# endif /* no NBPG */
+# endif /* no EXEC_PAGESIZE */
+# else /* no HAVE_SYS_PARAM_H */
+# define getpagesize() 8192 /* punt totally */
+# endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+int
+main ()
+{
+ char *data, *data2, *data3;
+ const char *cdata2;
+ int i, pagesize;
+ int fd, fd2;
+
+ pagesize = getpagesize ();
+
+ /* First, make a file with some known garbage in it. */
+ data = (char *) malloc (pagesize);
+ if (!data)
+ return 1;
+ for (i = 0; i < pagesize; ++i)
+ *(data + i) = rand ();
+ umask (0);
+ fd = creat ("conftest.mmap", 0600);
+ if (fd < 0)
+ return 2;
+ if (write (fd, data, pagesize) != pagesize)
+ return 3;
+ close (fd);
+
+ /* Next, check that the tail of a page is zero-filled. File must have
+ non-zero length, otherwise we risk SIGBUS for entire page. */
+ fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if (fd2 < 0)
+ return 4;
+ cdata2 = "";
+ if (write (fd2, cdata2, 1) != 1)
+ return 5;
+ data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L);
+ if (data2 == MAP_FAILED)
+ return 6;
+ for (i = 0; i < pagesize; ++i)
+ if (*(data2 + i))
+ return 7;
+ close (fd2);
+ if (munmap (data2, pagesize))
+ return 8;
+
+ /* Next, try to mmap the file at a fixed address which already has
+ something else allocated at it. If we can, also make sure that
+ we see the same garbage. */
+ fd = open ("conftest.mmap", O_RDWR);
+ if (fd < 0)
+ return 9;
+ if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED, fd, 0L))
+ return 10;
+ for (i = 0; i < pagesize; ++i)
+ if (*(data + i) != *(data2 + i))
+ return 11;
+
+ /* Finally, make sure that changes to the mapped area do not
+ percolate back to the file as seen by read(). (This is a bug on
+ some variants of i386 svr4.0.) */
+ for (i = 0; i < pagesize; ++i)
+ *(data2 + i) = *(data2 + i) + 1;
+ data3 = (char *) malloc (pagesize);
+ if (!data3)
+ return 12;
+ if (read (fd, data3, pagesize) != pagesize)
+ return 13;
+ for (i = 0; i < pagesize; ++i)
+ if (*(data + i) != *(data3 + i))
+ return 14;
+ close (fd);
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_func_mmap_fixed_mapped=yes
+else
+ ac_cv_func_mmap_fixed_mapped=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5
+$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; }
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+
+$as_echo "#define HAVE_MMAP 1" >>confdefs.h
+
+fi
+rm -f conftest.mmap conftest.txt
+
+for ac_func in gethostbyname gettimeofday memmove memset munmap regcomp select socket sqrt strcasecmp strchr strdup strerror strncasecmp strtol strtoul poll epoll_wait kqueue
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ac_config_files="$ac_config_files Makefile samples/Makefile src/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ test "x$cache_file" != "x/dev/null" &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by knot $as_me 0.8, which was
+generated by GNU Autoconf 2.67. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <knot-dns@labs.nic.cz>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+knot config.status 0.8
+configured by $0, generated by GNU Autoconf 2.67,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`'
+enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`'
+host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`'
+host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`'
+host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`'
+build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`'
+build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`'
+build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`'
+SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`'
+Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`'
+GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`'
+EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`'
+FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`'
+LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`'
+NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`'
+LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`'
+exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`'
+AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`'
+STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`'
+compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`'
+GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
+objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`'
+SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`'
+ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`'
+need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`'
+LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`'
+libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
+need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`'
+version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`'
+striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# Quote evaled strings.
+for var in SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+AR \
+AR_FLAGS \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+SHELL \
+ECHO \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_wl \
+lt_prog_compiler_pic \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_flag_spec_ld \
+hardcode_libdir_separator \
+fix_srcfile_path \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+finish_eval \
+old_striplib \
+striplib; do
+ case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec; do
+ case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Fix-up fallback echo if it was mangled by the above quoting rules.
+case \$lt_ECHO in
+*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\`
+ ;;
+esac
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "samples/Makefile") CONFIG_FILES="$CONFIG_FILES samples/Makefile" ;;
+ "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp=
+ trap 'exit_status=$?
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_t"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$tmp/stdin"
+ case $ac_file in
+ -) cat "$tmp/out" && rm -f "$tmp/out";;
+ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+ } >"$tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=""
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that does not interpret backslashes.
+ECHO=$lt_ECHO
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=$(( $* ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=${#1}
+}
+
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+}
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "X${3}" \
+ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "X${3}" \
+ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[^=]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "$@"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1+=\$2"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1=\$$1\$2"
+}
+
+_LT_EOF
+ ;;
+ esac
+
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..b824a43
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,141 @@
+# -*- Autoconf -*-
+
+AC_PREREQ([2.65])
+AC_INIT([knot], [0.8], [knot-dns@labs.nic.cz])
+AM_INIT_AUTOMAKE([gnu -Wall -Werror])
+AC_CONFIG_SRCDIR([src/knot/main.c])
+AC_CONFIG_HEADERS([src/config.h])
+AC_CONFIG_MACRO_DIR([m4])
+AC_USE_SYSTEM_EXTENSIONS([_GNU_SOURCE])
+AX_EXT
+
+# Enable maintainer mode by default for development
+AM_MAINTAINER_MODE([enable])
+
+# Initialize libtool
+LT_INIT
+
+# Checks for programs.
+AC_PROG_CC
+
+AC_CACHE_CHECK([for reentrant lex], [ac_cv_path_LEX],
+ [AC_PATH_PROGS_FEATURE_CHECK([LEX], [$LEX flex gflex],
+ [cat >conftest.l <<_ACEOF
+%{
+%}
+
+%option reentrant
+%option bison-bridge
+%option noinput
+%option nounput
+%option noreject
+
+BLANK [ \t\n]
+
+%%
+<<EOF>> return 0;
+%%
+_ACEOF
+_AC_DO_VAR(ac_path_LEX conftest.l)
+test $ac_status -eq 0 && ac_cv_path_LEX=$ac_path_LEX ac_path_LEX_found=true
+rm -f conftest.l lexyy.c lex.yy.c
+],
+[AC_MSG_ERROR([could not find lex that supports reentrant parsers])])])
+AC_SUBST([LEX], [$ac_cv_path_LEX])
+AM_PROG_LEX
+
+AC_PROG_YACC
+YACC_BISON=`bison --version | awk '{print $1;exit}'`
+if test "$YACC_BISON" != "bison"; then
+ AC_MSG_ERROR([GNU bison needed for reentrant parsers, set the \$YACC variable before running configure])
+fi
+AC_PROG_INSTALL
+
+# Set compiler compatibility flags
+AC_PROG_CPP_WERROR
+AC_PROG_CC_C99
+
+AC_ARG_ENABLE([ldns],
+ AC_HELP_STRING([--enable-ldns=yes|no], [Enable tests with ldns [default=no]]),
+ [case "${enableval}" in
+ yes) AC_SEARCH_LIBS([ldns_rr_list_pop_rrset], [ldns], [AC_DEFINE([HAVE_LDNS], [1], [ldns present])],
+ AC_MSG_ERROR([ldns not found])) ;;
+ no) ldns=false ;;
+ *) AC_MSG_ERROR([bad value ${enableval} for --enable-ldns]) ;;
+ esac],[ldns=false])
+
+# Debug level
+AC_ARG_ENABLE([debug],
+ AS_HELP_STRING([--enable-debug=brief|verbose|details], [enable given debug level [default=disabled]]),
+ # Not all shells support fall-through with ;& so I have to duplicate
+ [case "x${enableval}" in
+ xdetails)
+ AC_DEFINE([DEBUG_ENABLE_DETAILS], [1], [Enable details debugging messages.])
+ AC_DEFINE([DEBUG_ENABLE_VERBOSE], [1], [Enable verbose debugging messages.])
+ AC_DEFINE([DEBUG_ENABLE_BRIEF], [1], [Enable brief debugging messages.])
+ ;;
+ xverbose)
+ AC_DEFINE([DEBUG_ENABLE_VERBOSE], [1], [Enable verbose debugging messages.])
+ AC_DEFINE([DEBUG_ENABLE_BRIEF], [1], [Enable brief debugging messages.])
+ ;;
+ xbrief)
+ AC_DEFINE([DEBUG_ENABLE_BRIEF], [1], [Enable brief debugging messages.])
+ ;;
+ esac], [])
+
+# recvmmsg() (valgrind doesn't support it, so disable for debugging)
+AC_ARG_ENABLE([recvmmsg],
+ AS_HELP_STRING([--enable-recvmmsg=yes|no], [enable recvmmsg() network API under Linux (kernel support required) (set to 'no' if you have trouble running server under valgrind) [default=yes]]),
+ [case "${enableval}" in
+ yes)
+ AC_DEFINE([ENABLE_RECVMMSG], [1], [recvmmsg enabled])
+ ;;
+ no)
+ recvmmsg=false
+ ;;
+ *)
+ AC_MSG_ERROR([bad value ${enableval} for --enable-recvmmsg])
+ ;;
+ esac], [
+ AC_DEFINE([ENABLE_RECVMMSG], [1], [recvmmsg enabled])
+ recvmmsg=true
+ ])
+
+# Checks for libraries.
+# FIXME: Replace `main' with a function in `-lm':
+# TODO: check if paths exist before appending
+CFLAGS="$CFLAGS -I/usr/local/include"
+LDFLAGS="$LDFLAGS -L/usr/local/lib"
+AC_SEARCH_LIBS([pow], [m])
+AC_SEARCH_LIBS([pthread_create], [pthread], [], [AC_MSG_ERROR([pthreads not found])])
+AC_SEARCH_LIBS([rcu_set_pointer_sym], [urcu], [], [AC_MSG_ERROR([liburcu not found])])
+AC_SEARCH_LIBS([dlopen], [dl])
+#AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([librt not found])])
+AC_SEARCH_LIBS([OpenSSL_add_all_digests], [crypto],[], [AC_MSG_ERROR([libcrypto not found])])
+#AC_SEARCH_LIBS([ldns_rr_list_pop_rrset], [ldns], [], [AC_MSG_ERROR([libldns not found])])
+
+# Checks for header files.
+AC_HEADER_RESOLV
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stdint.h stdlib.h string.h strings.h sys/socket.h sys/time.h syslog.h unistd.h urcu.h ev.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_INLINE
+AC_TYPE_INT64_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT64_T
+AC_TYPE_UINT8_T
+
+# Checks for library functions.
+AC_FUNC_FORK
+AC_FUNC_MMAP
+AC_CHECK_FUNCS([gethostbyname gettimeofday memmove memset munmap regcomp select socket sqrt strcasecmp strchr strdup strerror strncasecmp strtol strtoul poll epoll_wait kqueue])
+
+AC_CONFIG_FILES([Makefile
+ samples/Makefile
+ src/Makefile])
+AC_OUTPUT
diff --git a/depcomp b/depcomp
new file mode 100755
index 0000000..df8eea7
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,630 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
+# Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u="sed s,\\\\\\\\,/,g"
+ depmode=msvisualcpp
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> "$depfile"
+ echo >> "$depfile"
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add `dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..6781b98
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,520 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2009-04-28.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dst_arg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ -*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test -z "$d" && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/knot.sample.conf.in b/knot.sample.conf.in
new file mode 100644
index 0000000..db5c587
--- /dev/null
+++ b/knot.sample.conf.in
@@ -0,0 +1,18 @@
+system {
+ identity "@package@ @version@";
+ storage "@localstatedir@/@package@";
+}
+
+interfaces {
+ ipv4 { address 127.0.0.1@53; }
+}
+
+zones {
+ example.com {
+ file "@sysconfdir@/example.com.zone";
+ }
+}
+
+log {
+ syslog { any warning, error, notice; }
+}
diff --git a/ltmain.sh b/ltmain.sh
new file mode 100755
index 0000000..d88da2c
--- /dev/null
+++ b/ltmain.sh
@@ -0,0 +1,8413 @@
+# Generated from ltmain.m4sh.
+
+# ltmain.sh (GNU libtool) 2.2.6b
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+# --config show all configuration variables
+# --debug enable verbose shell tracing
+# -n, --dry-run display commands without modifying any files
+# --features display basic configuration information and exit
+# --mode=MODE use operation mode MODE
+# --preserve-dup-deps don't remove duplicate dependency libraries
+# --quiet, --silent don't print informational messages
+# --tag=TAG use configuration variables from tag TAG
+# -v, --verbose print informational messages (default)
+# --version print version information
+# -h, --help print short or long help message
+#
+# MODE must be one of the following:
+#
+# clean remove files from the build directory
+# compile compile a source file into a libtool object
+# execute automatically set library path, then run a program
+# finish complete the installation of libtool libraries
+# install install libraries or executables
+# link create a library or an executable
+# uninstall remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+# host-triplet: $host
+# shell: $SHELL
+# compiler: $LTCC
+# compiler flags: $LTCFLAGS
+# linker: $LD (gnu? $with_gnu_ld)
+# $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2
+# automake: $automake_version
+# autoconf: $autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION="2.2.6b Debian-2.2.6b-2"
+TIMESTAMP=""
+package_revision=1.3017
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# NLS nuisances: We save the old values to restore during execute mode.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test \"\${$lt_var+set}\" = set; then
+ save_$lt_var=\$$lt_var
+ $lt_var=C
+ export $lt_var
+ lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+ lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+ fi"
+done
+
+$lt_unset CDPATH
+
+
+
+
+
+: ${CP="cp -f"}
+: ${ECHO="echo"}
+: ${EGREP="/bin/grep -E"}
+: ${FGREP="/bin/grep -F"}
+: ${GREP="/bin/grep"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SED="/bin/sed"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" $lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+ func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+}
+
+# Generated shell functions inserted here.
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# The name of this program:
+# In the unlikely event $progname began with a '-', it would play havoc with
+# func_echo (imagine progname=-n), so we prepend ./ in that case:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+case $progname in
+ -*) progname=./$progname ;;
+esac
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+ [\\/]*|[A-Za-z]:\\*) ;;
+ *[\\/]*)
+ progdir=$func_dirname_result
+ progdir=`cd "$progdir" && pwd`
+ progpath="$progdir/$progname"
+ ;;
+ *)
+ save_IFS="$IFS"
+ IFS=:
+ for progdir in $PATH; do
+ IFS="$save_IFS"
+ test -x "$progdir/$progname" && break
+ done
+ IFS="$save_IFS"
+ test -n "$progdir" || progdir=`pwd`
+ progpath="$progdir/$progname"
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same. If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'. `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+ s/$bs4/&\\
+/g
+ s/^$bs2$dollar/$bs&/
+ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+ s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+ $ECHO "$progname${mode+: }$mode: $*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+ $opt_verbose && func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+ $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+ $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2
+
+ # bash bug again:
+ :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ func_error ${1+"$@"}
+ func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information." ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+ $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+ my_directory_path="$1"
+ my_dir_list=
+
+ if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+ # Protect directory names starting with `-'
+ case $my_directory_path in
+ -*) my_directory_path="./$my_directory_path" ;;
+ esac
+
+ # While some portion of DIR does not yet exist...
+ while test ! -d "$my_directory_path"; do
+ # ...make a list in topmost first order. Use a colon delimited
+ # list incase some portion of path contains whitespace.
+ my_dir_list="$my_directory_path:$my_dir_list"
+
+ # If the last portion added has no slash in it, the list is done
+ case $my_directory_path in */*) ;; *) break ;; esac
+
+ # ...otherwise throw away the child directory and loop
+ my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"`
+ done
+ my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'`
+
+ save_mkdir_p_IFS="$IFS"; IFS=':'
+ for my_dir in $my_dir_list; do
+ IFS="$save_mkdir_p_IFS"
+ # mkdir can fail with a `File exist' error if two processes
+ # try to create one of the directories concurrently. Don't
+ # stop in that case!
+ $MKDIR "$my_dir" 2>/dev/null || :
+ done
+ IFS="$save_mkdir_p_IFS"
+
+ # Bail out if we (or some other process) failed to create a directory.
+ test -d "$my_directory_path" || \
+ func_fatal_error "Failed to create \`$1'"
+ fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+ my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+ if test "$opt_dry_run" = ":"; then
+ # Return a directory name, but don't create it in dry-run mode
+ my_tmpdir="${my_template}-$$"
+ else
+
+ # If mktemp works, use that first and foremost
+ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$my_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+ save_mktempdir_umask=`umask`
+ umask 0077
+ $MKDIR "$my_tmpdir"
+ umask $save_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$my_tmpdir" || \
+ func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+ fi
+
+ $ECHO "X$my_tmpdir" | $Xsed
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+ case $1 in
+ *[\\\`\"\$]*)
+ func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;;
+ *)
+ func_quote_for_eval_unquoted_result="$1" ;;
+ esac
+
+ case $func_quote_for_eval_unquoted_result in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and and variable
+ # expansion for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+ ;;
+ *)
+ func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+ esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+ case $1 in
+ *[\\\`\"]*)
+ my_arg=`$ECHO "X$1" | $Xsed \
+ -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+ *)
+ my_arg="$1" ;;
+ esac
+
+ case $my_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting and command substitution for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ my_arg="\"$my_arg\""
+ ;;
+ esac
+
+ func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$my_cmd"
+ my_status=$?
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it. Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$lt_user_locale
+ $my_cmd"
+ my_status=$?
+ eval "$lt_safe_locale"
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+
+
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / {
+ s/^# //
+ s/^# *$//
+ s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+ p
+ }' < "$progpath"
+ exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+ $SED -n '/^# Usage:/,/# -h/ {
+ s/^# //
+ s/^# *$//
+ s/\$progname/'$progname'/
+ p
+ }' < "$progpath"
+ $ECHO
+ $ECHO "run \`$progname --help | more' for full usage"
+ exit $?
+}
+
+# func_help
+# Echo long help message to standard output and exit.
+func_help ()
+{
+ $SED -n '/^# Usage:/,/# Report bugs to/ {
+ s/^# //
+ s/^# *$//
+ s*\$progname*'$progname'*
+ s*\$host*'"$host"'*
+ s*\$SHELL*'"$SHELL"'*
+ s*\$LTCC*'"$LTCC"'*
+ s*\$LTCFLAGS*'"$LTCFLAGS"'*
+ s*\$LD*'"$LD"'*
+ s/\$with_gnu_ld/'"$with_gnu_ld"'/
+ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/
+ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/
+ p
+ }' < "$progpath"
+ exit $?
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+ func_error "missing argument for $1"
+ exit_cmd=exit
+}
+
+exit_cmd=:
+
+
+
+
+
+# Check that we have a working $ECHO.
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then
+ # Yippee, $ECHO works!
+ :
+else
+ # Restart under the correct shell, and then maybe $ECHO will work.
+ exec $SHELL "$progpath" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit $EXIT_SUCCESS
+fi
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+# $mode is unset
+nonopt=
+execute_dlfiles=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+opt_dry_run=false
+opt_duplicate_deps=false
+opt_silent=false
+opt_debug=:
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+ func_error ${1+"$@"}
+ func_error "See the $PACKAGE documentation for more information."
+ func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+ re_begincf='^# ### BEGIN LIBTOOL'
+ re_endcf='^# ### END LIBTOOL'
+
+ # Default configuration.
+ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+ done
+
+ exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+ $ECHO "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ $ECHO "enable shared libraries"
+ else
+ $ECHO "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ $ECHO "enable static libraries"
+ else
+ $ECHO "disable static libraries"
+ fi
+
+ exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+ # Global variable:
+ tagname="$1"
+
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
+
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
+ *)
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
+}
+
+# Parse options once, thoroughly. This comes as soon as possible in
+# the script to make things like `libtool --version' happen quickly.
+{
+
+ # Shorthand for --mode=foo, only valid as the first argument
+ case $1 in
+ clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+ compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+ execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+ finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+ link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+ uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+ esac
+
+ # Parse non-mode specific arguments:
+ while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --config) func_config ;;
+
+ --debug) preserve_args="$preserve_args $opt"
+ func_echo "enabling shell trace mode"
+ opt_debug='set -x'
+ $opt_debug
+ ;;
+
+ -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ execute_dlfiles="$execute_dlfiles $1"
+ shift
+ ;;
+
+ --dry-run | -n) opt_dry_run=: ;;
+ --features) func_features ;;
+ --finish) mode="finish" ;;
+
+ --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ case $1 in
+ # Valid mode arguments:
+ clean) ;;
+ compile) ;;
+ execute) ;;
+ finish) ;;
+ install) ;;
+ link) ;;
+ relink) ;;
+ uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $opt"
+ exit_cmd=exit
+ break
+ ;;
+ esac
+
+ mode="$1"
+ shift
+ ;;
+
+ --preserve-dup-deps)
+ opt_duplicate_deps=: ;;
+
+ --quiet|--silent) preserve_args="$preserve_args $opt"
+ opt_silent=:
+ ;;
+
+ --verbose| -v) preserve_args="$preserve_args $opt"
+ opt_silent=false
+ ;;
+
+ --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ preserve_args="$preserve_args $opt $1"
+ func_enable_tag "$1" # tagname is set here
+ shift
+ ;;
+
+ # Separate optargs to long options:
+ -dlopen=*|--mode=*|--tag=*)
+ func_opt_split "$opt"
+ set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"}
+ shift
+ ;;
+
+ -\?|-h) func_usage ;;
+ --help) opt_help=: ;;
+ --version) func_version ;;
+
+ -*) func_fatal_help "unrecognized option \`$opt'" ;;
+
+ *) nonopt="$opt"
+ break
+ ;;
+ esac
+ done
+
+
+ case $host in
+ *cygwin* | *mingw* | *pw32* | *cegcc*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_duplicate_deps
+ ;;
+ esac
+
+ # Having warned about all mis-specified options, bail out if
+ # anything was wrong.
+ $exit_cmd $EXIT_FAILURE
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+ fi
+
+ exit $EXIT_MISMATCH
+ fi
+}
+
+
+## ----------- ##
+## Main. ##
+## ----------- ##
+
+$opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+
+ if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ func_fatal_configuration "not configured to build any kind of library"
+ fi
+
+ test -z "$mode" && func_fatal_error "error: you must specify a MODE."
+
+
+ # Darwin sucks
+ eval std_shrext=\"$shrext_cmds\"
+
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ func_error "unrecognized option \`-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$progname --help --mode=$mode' for more information."
+}
+
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+ test -f "$1" &&
+ $SED -e 4q "$1" 2>/dev/null \
+ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs. To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway. Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+ lalib_p=no
+ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+ for lalib_p_l in 1 2 3 4
+ do
+ read lalib_p_line
+ case "$lalib_p_line" in
+ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+ esac
+ done
+ exec 0<&5 5<&-
+ fi
+ test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+ func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+ func_ltwrapper_exec_suffix=
+ case $1 in
+ *.exe) ;;
+ *) func_ltwrapper_exec_suffix=.exe ;;
+ esac
+ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+ func_ltwrapper_scriptname_result=""
+ if func_ltwrapper_executable_p "$1"; then
+ func_dirname_and_basename "$1" "" "."
+ func_stripname '' '.exe' "$func_basename_result"
+ func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+ fi
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+ $opt_debug
+ save_ifs=$IFS; IFS='~'
+ for cmd in $1; do
+ IFS=$save_ifs
+ eval cmd=\"$cmd\"
+ func_show_eval "$cmd" "${2-:}"
+ done
+ IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)! Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+ $opt_debug
+ case $1 in
+ */* | *\\*) . "$1" ;;
+ *) . "./$1" ;;
+ esac
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ $opt_debug
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ func_quote_for_eval "$arg"
+ CC_quoted="$CC_quoted $func_quote_for_eval_result"
+ done
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ func_quote_for_eval "$arg"
+ CC_quoted="$CC_quoted $func_quote_for_eval_result"
+ done
+ case "$@ " in
+ " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ func_echo "unable to infer tagged configuration"
+ func_fatal_error "specify a tag with \`--tag'"
+# else
+# func_verbose "using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+ write_libobj=${1}
+ if test "$build_libtool_libs" = yes; then
+ write_lobj=\'${2}\'
+ else
+ write_lobj=none
+ fi
+
+ if test "$build_old_libs" = yes; then
+ write_oldobj=\'${3}\'
+ else
+ write_oldobj=none
+ fi
+
+ $opt_dry_run || {
+ cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+ $MV "${write_libobj}T" "${write_libobj}"
+ }
+}
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+ $opt_debug
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+ pie_flag=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ test -n "$libobj" && \
+ func_fatal_error "you cannot specify \`-o' more than once"
+ arg_mode=target
+ continue
+ ;;
+
+ -pie | -fpie | -fPIE)
+ pie_flag="$pie_flag $arg"
+ continue
+ ;;
+
+ -shared | -static | -prefer-pic | -prefer-non-pic)
+ later="$later $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$arg"
+ lastarg="$lastarg $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$lastarg"
+ lastarg=$func_stripname_result
+
+ # Add the arguments to base_compile.
+ base_compile="$base_compile $lastarg"
+ continue
+ ;;
+
+ *)
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ func_quote_for_eval "$lastarg"
+ base_compile="$base_compile $func_quote_for_eval_result"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ func_fatal_error "you must specify an argument for -Xcompile"
+ ;;
+ target)
+ func_fatal_error "you must specify a target with \`-o'"
+ ;;
+ *)
+ # Get the name of the library object.
+ test -z "$libobj" && {
+ func_basename "$srcfile"
+ libobj="$func_basename_result"
+ }
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ case $libobj in
+ *.[cCFSifmso] | \
+ *.ada | *.adb | *.ads | *.asm | \
+ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+ *.[fF][09]? | *.for | *.java | *.obj | *.sx)
+ func_xform "$libobj"
+ libobj=$func_xform_result
+ ;;
+ esac
+
+ case $libobj in
+ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+ *)
+ func_fatal_error "cannot determine name of library object from \`$libobj'"
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ continue
+ ;;
+
+ -static)
+ build_libtool_libs=no
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ func_quote_for_eval "$libobj"
+ test "X$libobj" != "X$func_quote_for_eval_result" \
+ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && func_warning "libobj name \`$libobj' may not contain shell special characters."
+ func_dirname_and_basename "$obj" "/" ""
+ objname="$func_basename_result"
+ xdir="$func_dirname_result"
+ lobj=${xdir}$objdir/$objname
+
+ test -z "$base_compile" && \
+ func_fatal_help "you must specify a compilation command"
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2* | cegcc*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+ removelist="$removelist $output_obj"
+ $ECHO "$srcfile" > "$lockfile"
+ fi
+
+ $opt_dry_run || $RM $removelist
+ removelist="$removelist $lockfile"
+ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+ func_quote_for_eval "$srcfile"
+ qsrcfile=$func_quote_for_eval_result
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ func_mkdir_p "$xdir$objdir"
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ command="$command -o $lobj"
+ fi
+
+ func_show_eval_locale "$command" \
+ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ func_show_eval '$MV "$output_obj" "$lobj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+
+ # Allow error messages only from the first compilation.
+ if test "$suppress_opt" = yes; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile$pie_flag"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ func_show_eval_locale "$command" \
+ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ func_show_eval '$MV "$output_obj" "$obj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+ fi
+
+ $opt_dry_run || {
+ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ removelist=$lockfile
+ $RM "$lockfile"
+ fi
+ }
+
+ exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+test "$mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+ # We need to display help for each of the modes.
+ case $mode in
+ "")
+ # Generic help is extracted from the usage comments
+ # at the start of this file.
+ func_help
+ ;;
+
+ clean)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ compile)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -no-suppress do not suppress compiler output for multiple passes
+ -prefer-pic try to building PIC objects only
+ -prefer-non-pic try to building non-PIC objects only
+ -shared do not build a \`.o' file suitable for static linking
+ -static only build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+ execute)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+ finish)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+ install)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+ -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+ link)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -shared only do dynamic linking of libtool libraries
+ -shrext SUFFIX override the standard shared library file extension
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+ -weak LIBNAME declare that the target provides the LIBNAME interface
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+ uninstall)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ *)
+ func_fatal_help "invalid operation mode \`$mode'"
+ ;;
+ esac
+
+ $ECHO
+ $ECHO "Try \`$progname --help' for more information about other modes."
+
+ exit $?
+}
+
+ # Now that we've collected a possible --mode arg, show help if necessary
+ $opt_help && func_mode_help
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+ $opt_debug
+ # The first argument is the command name.
+ cmd="$nonopt"
+ test -z "$cmd" && \
+ func_fatal_help "you must specify a COMMAND"
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ test -f "$file" \
+ || func_fatal_help "\`$file' is not a file"
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+ func_source "$file"
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && \
+ func_warning "\`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ ;;
+
+ *)
+ func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -*) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if func_ltwrapper_script_p "$file"; then
+ func_source "$file"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ elif func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ func_source "$func_ltwrapper_scriptname_result"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ func_quote_for_eval "$file"
+ args="$args $func_quote_for_eval_result"
+ done
+
+ if test "X$opt_dry_run" = Xfalse; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ else
+ $lt_unset $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ $ECHO "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+ $opt_debug
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $opt_dry_run || eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ $opt_silent && exit $EXIT_SUCCESS
+
+ $ECHO "X----------------------------------------------------------------------" | $Xsed
+ $ECHO "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $ECHO " $libdir"
+ done
+ $ECHO
+ $ECHO "If you ever happen to want to link against installed libraries"
+ $ECHO "in a given directory, LIBDIR, you must either use libtool, and"
+ $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ $ECHO "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ $ECHO " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ $ECHO " - add LIBDIR to the \`$runpath_var' environment variable"
+ $ECHO " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $ECHO " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $ECHO " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ $ECHO
+
+ $ECHO "See any operating system documentation about shared libraries for"
+ case $host in
+ solaris2.[6789]|solaris2.1[0-9])
+ $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+ $ECHO "pages."
+ ;;
+ *)
+ $ECHO "more information, such as the ld(1) and ld.so(8) manual pages."
+ ;;
+ esac
+ $ECHO "X----------------------------------------------------------------------" | $Xsed
+ exit $EXIT_SUCCESS
+}
+
+test "$mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+ $opt_debug
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ $ECHO "X$nonopt" | $GREP shtool >/dev/null; then
+ # Aesthetically quote it.
+ func_quote_for_eval "$nonopt"
+ install_prog="$func_quote_for_eval_result "
+ arg=$1
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ func_quote_for_eval "$arg"
+ install_prog="$install_prog$func_quote_for_eval_result"
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ for arg
+ do
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f)
+ case " $install_prog " in
+ *[\\\ /]cp\ *) ;;
+ *) prev=$arg ;;
+ esac
+ ;;
+ -g | -m | -o)
+ prev=$arg
+ ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ func_quote_for_eval "$arg"
+ install_prog="$install_prog $func_quote_for_eval_result"
+ done
+
+ test -z "$install_prog" && \
+ func_fatal_help "you must specify an install program"
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prev' option requires an argument"
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ func_fatal_help "no file or destination specified"
+ else
+ func_fatal_help "you must specify a destination"
+ fi
+ fi
+
+ # Strip any trailing slash from the destination.
+ func_stripname '' '/' "$dest"
+ dest=$func_stripname_result
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ func_dirname_and_basename "$dest" "" "."
+ destdir="$func_dirname_result"
+ destname="$func_basename_result"
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files; shift
+ test "$#" -gt 1 && \
+ func_fatal_help "\`$dest' is not a directory"
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ func_fatal_help "\`$destdir' must be an absolute directory name"
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$file' is not a valid libtool archive"
+
+ library_names=
+ old_library=
+ relink_command=
+ func_source "$file"
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ func_dirname "$file" "/" ""
+ dir="$func_dirname_result"
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ test "$inst_prefix_dir" = "$destdir" && \
+ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"`
+ fi
+
+ func_warning "relinking \`$file'"
+ func_show_eval "$relink_command" \
+ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names; shift
+ if test -n "$1"; then
+ realname="$1"
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \
+ 'exit $?'
+ tstripme="$stripme"
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $realname in
+ *.dll.a)
+ tstripme=""
+ ;;
+ esac
+ ;;
+ esac
+ if test -n "$tstripme" && test -n "$striplib"; then
+ func_show_eval "$striplib $destdir/$realname" 'exit $?'
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try `ln -sf' first, because the `ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ test "$linkname" != "$realname" \
+ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ func_execute_cmds "$postinstall_cmds" 'exit $?'
+ fi
+
+ # Install the pseudo-library for information purposes.
+ func_basename "$file"
+ name="$func_basename_result"
+ instname="$dir/$name"i
+ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ func_lo2o "$destfile"
+ staticdest=$func_lo2o_result
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ func_fatal_help "cannot copy a libtool object to \`$destfile'"
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ test -n "$destfile" && \
+ func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ func_lo2o "$file"
+ staticobj=$func_lo2o_result
+ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin* | *mingw*)
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ wrapper=$func_ltwrapper_scriptname_result
+ else
+ func_stripname '' '.exe' "$file"
+ wrapper=$func_stripname_result
+ fi
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if func_ltwrapper_script_p "$wrapper"; then
+ notinst_deplibs=
+ relink_command=
+
+ func_source "$wrapper"
+
+ # Check the variables that should have been set.
+ test -z "$generated_by_libtool_version" && \
+ func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ func_source "$lib"
+ fi
+ libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ func_warning "\`$lib' has not been installed in \`$libdir'"
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ func_source "$wrapper"
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ $opt_dry_run || {
+ if test "$finalize" = yes; then
+ tmpdir=`func_mktempdir`
+ func_basename "$file$stripped_ext"
+ file="$func_basename_result"
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $opt_silent || {
+ func_quote_for_expand "$relink_command"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ if eval "$relink_command"; then :
+ else
+ func_error "error: relink \`$file' with the above command before installing it"
+ $opt_dry_run || ${RM}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ func_warning "cannot relink \`$file'"
+ fi
+ }
+ else
+ # Install the binary that we compiled earlier.
+ file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ func_stripname '' '.exe' "$destfile"
+ destfile=$func_stripname_result
+ ;;
+ esac
+ ;;
+ esac
+ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+ $opt_dry_run || if test -n "$outputname"; then
+ ${RM}r "$tmpdir"
+ fi
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ func_basename "$file"
+ name="$func_basename_result"
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ func_show_eval "$old_striplib $oldlib" 'exit $?'
+ fi
+
+ # Do each command in the postinstall commands.
+ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+ done
+
+ test -n "$future_libdirs" && \
+ func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ $opt_dry_run && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+ $opt_debug
+ my_outputname="$1"
+ my_originator="$2"
+ my_pic_p="${3-no}"
+ my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+ my_dlsyms=
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ my_dlsyms="${my_outputname}S.c"
+ else
+ func_error "not configured to extract global symbols from dlpreopened files"
+ fi
+ fi
+
+ if test -n "$my_dlsyms"; then
+ case $my_dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${my_outputname}.nm"
+
+ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+ # Parse the name list into a source file.
+ func_verbose "creating $output_objdir/$my_dlsyms"
+
+ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ func_verbose "generating symbol list for \`$output'"
+
+ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ for progfile in $progfiles; do
+ func_verbose "extracting global C symbols from \`$progfile'"
+ $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $opt_dry_run || {
+ eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $opt_dry_run || {
+ eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$outputname.exp"
+ $opt_dry_run || {
+ $RM $export_symbols
+ eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ else
+ $opt_dry_run || {
+ eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ case $host in
+ *cygwin | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ fi
+ fi
+
+ for dlprefile in $dlprefiles; do
+ func_verbose "extracting global C symbols from \`$dlprefile'"
+ func_basename "$dlprefile"
+ name="$func_basename_result"
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ done
+
+ $opt_dry_run || {
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if $GREP -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ $GREP -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+ else
+ $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms"
+ fi
+
+ $ECHO >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols. */
+typedef struct {
+ const char *name;
+ void *address;
+} lt_dlsymlist;
+"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ $ECHO >> "$output_objdir/$my_dlsyms" "\
+/* DATA imports from DLLs on WIN32 con't be const, because
+ runtime relocations are performed -- see ld's documentation
+ on pseudo-relocs. */"
+ lt_dlsym_const= ;;
+ *osf5*)
+ echo >> "$output_objdir/$my_dlsyms" "\
+/* This system does not cope well with relocations in const data */"
+ lt_dlsym_const= ;;
+ *)
+ lt_dlsym_const=const ;;
+ esac
+
+ $ECHO >> "$output_objdir/$my_dlsyms" "\
+extern $lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+$lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+ { \"$my_originator\", (void *) 0 },"
+
+ case $need_lib_prefix in
+ no)
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ *)
+ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ esac
+ $ECHO >> "$output_objdir/$my_dlsyms" "\
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ } # !$opt_dry_run
+
+ pic_flag_for_symtable=
+ case "$compile_command " in
+ *" -static "*) ;;
+ *)
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+ *-*-hpux*)
+ pic_flag_for_symtable=" $pic_flag" ;;
+ *)
+ if test "X$my_pic_p" != Xno; then
+ pic_flag_for_symtable=" $pic_flag"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ symtab_cflags=
+ for arg in $LTCFLAGS; do
+ case $arg in
+ -pie | -fpie | -fPIE) ;;
+ *) symtab_cflags="$symtab_cflags $arg" ;;
+ esac
+ done
+
+ # Now compile the dynamic symbol file.
+ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+ # Clean up the generated files.
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+ # Transform the symbol file into the correct name.
+ symfileobj="$output_objdir/${my_outputname}S.$objext"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ if test -f "$output_objdir/$my_outputname.def"; then
+ compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ else
+ compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+ fi
+ ;;
+ *)
+ compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+ ;;
+ esac
+ ;;
+ *)
+ func_fatal_error "unknown suffix for \`$my_dlsyms'"
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+ finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+ fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+func_win32_libid ()
+{
+ $opt_debug
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+ $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+ win32_nmres=`eval $NM -f posix -A $1 |
+ $SED -n -e '
+ 1,100{
+ / I /{
+ s,.*,import,
+ p
+ q
+ }
+ }'`
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $ECHO "$win32_libid_type"
+}
+
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ $opt_debug
+ f_ex_an_ar_dir="$1"; shift
+ f_ex_an_ar_oldlib="$1"
+ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?'
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+ fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ $opt_debug
+ my_gentop="$1"; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=""
+ my_xlib=""
+ my_xabs=""
+ my_xdir=""
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ func_basename "$my_xlib"
+ my_xlib="$func_basename_result"
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ func_arith $extracted_serial + 1
+ extracted_serial=$func_arith_result
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir="$my_gentop/$my_xlib_u"
+
+ func_mkdir_p "$my_xdir"
+
+ case $host in
+ *-darwin*)
+ func_verbose "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ $opt_dry_run || {
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ darwin_base_archive=`basename "$darwin_archive"`
+ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches ; do
+ func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ cd "$darwin_curdir"
+ $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ done # $darwin_arches
+ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd $darwin_orig_dir
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ } # !$opt_dry_run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+
+ func_extract_archives_result="$my_oldobjs"
+}
+
+
+
+# func_emit_wrapper_part1 [arg=no]
+#
+# Emit the first part of a libtool wrapper script on stdout.
+# For more information, see the description associated with
+# func_emit_wrapper(), below.
+func_emit_wrapper_part1 ()
+{
+ func_emit_wrapper_part1_arg1=no
+ if test -n "$1" ; then
+ func_emit_wrapper_part1_arg1=$1
+ fi
+
+ $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='$macro_version'
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$ECHO are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ ECHO=\"$qecho\"
+ file=\"\$0\"
+ # Make sure echo works.
+ if test \"X\$1\" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then
+ # Yippee, \$ECHO works!
+ :
+ else
+ # Restart under the correct shell, and then maybe \$ECHO will work.
+ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+ fi
+ fi\
+"
+ $ECHO "\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+ done
+"
+}
+# end: func_emit_wrapper_part1
+
+# func_emit_wrapper_part2 [arg=no]
+#
+# Emit the second part of a libtool wrapper script on stdout.
+# For more information, see the description associated with
+# func_emit_wrapper(), below.
+func_emit_wrapper_part2 ()
+{
+ func_emit_wrapper_part2_arg1=no
+ if test -n "$1" ; then
+ func_emit_wrapper_part2_arg1=$1
+ fi
+
+ $ECHO "\
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $ECHO "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" ||
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $MKDIR \"\$progdir\"
+ else
+ $RM \"\$progdir/\$file\"
+ fi"
+
+ $ECHO "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $ECHO \"\$relink_command_output\" >&2
+ $RM \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $RM \"\$progdir/\$program\";
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $RM \"\$progdir/\$file\"
+ fi"
+ else
+ $ECHO "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $ECHO "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $ECHO "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $ECHO "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $ECHO "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2* | *-cegcc*)
+ $ECHO "\
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $ECHO "\
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $ECHO "\
+ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+ exit 1
+ fi
+ else
+ # The program doesn't exist.
+ \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+ $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+}
+# end: func_emit_wrapper_part2
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable. Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take. If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory. This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+ func_emit_wrapper_arg1=no
+ if test -n "$1" ; then
+ func_emit_wrapper_arg1=$1
+ fi
+
+ # split this up so that func_emit_cwrapperexe_src
+ # can call each part independently.
+ func_emit_wrapper_part1 "${func_emit_wrapper_arg1}"
+ func_emit_wrapper_part2 "${func_emit_wrapper_arg1}"
+}
+
+
+# func_to_host_path arg
+#
+# Convert paths to host format when used with build tools.
+# Intended for use with "native" mingw (where libtool itself
+# is running under the msys shell), or in the following cross-
+# build environments:
+# $build $host
+# mingw (msys) mingw [e.g. native]
+# cygwin mingw
+# *nix + wine mingw
+# where wine is equipped with the `winepath' executable.
+# In the native mingw case, the (msys) shell automatically
+# converts paths for any non-msys applications it launches,
+# but that facility isn't available from inside the cwrapper.
+# Similar accommodations are necessary for $host mingw and
+# $build cygwin. Calling this function does no harm for other
+# $host/$build combinations not listed above.
+#
+# ARG is the path (on $build) that should be converted to
+# the proper representation for $host. The result is stored
+# in $func_to_host_path_result.
+func_to_host_path ()
+{
+ func_to_host_path_result="$1"
+ if test -n "$1" ; then
+ case $host in
+ *mingw* )
+ lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+ case $build in
+ *mingw* ) # actually, msys
+ # awkward: cmd appends spaces to result
+ lt_sed_strip_trailing_spaces="s/[ ]*\$//"
+ func_to_host_path_tmp1=`( cmd //c echo "$1" |\
+ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""`
+ func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
+ $SED -e "$lt_sed_naive_backslashify"`
+ ;;
+ *cygwin* )
+ func_to_host_path_tmp1=`cygpath -w "$1"`
+ func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
+ $SED -e "$lt_sed_naive_backslashify"`
+ ;;
+ * )
+ # Unfortunately, winepath does not exit with a non-zero
+ # error code, so we are forced to check the contents of
+ # stdout. On the other hand, if the command is not
+ # found, the shell will set an exit code of 127 and print
+ # *an error message* to stdout. So we must check for both
+ # error code of zero AND non-empty stdout, which explains
+ # the odd construction:
+ func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null`
+ if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then
+ func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
+ $SED -e "$lt_sed_naive_backslashify"`
+ else
+ # Allow warning below.
+ func_to_host_path_result=""
+ fi
+ ;;
+ esac
+ if test -z "$func_to_host_path_result" ; then
+ func_error "Could not determine host path corresponding to"
+ func_error " '$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback:
+ func_to_host_path_result="$1"
+ fi
+ ;;
+ esac
+ fi
+}
+# end: func_to_host_path
+
+# func_to_host_pathlist arg
+#
+# Convert pathlists to host format when used with build tools.
+# See func_to_host_path(), above. This function supports the
+# following $build/$host combinations (but does no harm for
+# combinations not listed here):
+# $build $host
+# mingw (msys) mingw [e.g. native]
+# cygwin mingw
+# *nix + wine mingw
+#
+# Path separators are also converted from $build format to
+# $host format. If ARG begins or ends with a path separator
+# character, it is preserved (but converted to $host format)
+# on output.
+#
+# ARG is a pathlist (on $build) that should be converted to
+# the proper representation on $host. The result is stored
+# in $func_to_host_pathlist_result.
+func_to_host_pathlist ()
+{
+ func_to_host_pathlist_result="$1"
+ if test -n "$1" ; then
+ case $host in
+ *mingw* )
+ lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+ # Remove leading and trailing path separator characters from
+ # ARG. msys behavior is inconsistent here, cygpath turns them
+ # into '.;' and ';.', and winepath ignores them completely.
+ func_to_host_pathlist_tmp2="$1"
+ # Once set for this call, this variable should not be
+ # reassigned. It is used in tha fallback case.
+ func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\
+ $SED -e 's|^:*||' -e 's|:*$||'`
+ case $build in
+ *mingw* ) # Actually, msys.
+ # Awkward: cmd appends spaces to result.
+ lt_sed_strip_trailing_spaces="s/[ ]*\$//"
+ func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\
+ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""`
+ func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\
+ $SED -e "$lt_sed_naive_backslashify"`
+ ;;
+ *cygwin* )
+ func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"`
+ func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\
+ $SED -e "$lt_sed_naive_backslashify"`
+ ;;
+ * )
+ # unfortunately, winepath doesn't convert pathlists
+ func_to_host_pathlist_result=""
+ func_to_host_pathlist_oldIFS=$IFS
+ IFS=:
+ for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do
+ IFS=$func_to_host_pathlist_oldIFS
+ if test -n "$func_to_host_pathlist_f" ; then
+ func_to_host_path "$func_to_host_pathlist_f"
+ if test -n "$func_to_host_path_result" ; then
+ if test -z "$func_to_host_pathlist_result" ; then
+ func_to_host_pathlist_result="$func_to_host_path_result"
+ else
+ func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result"
+ fi
+ fi
+ fi
+ IFS=:
+ done
+ IFS=$func_to_host_pathlist_oldIFS
+ ;;
+ esac
+ if test -z "$func_to_host_pathlist_result" ; then
+ func_error "Could not determine the host path(s) corresponding to"
+ func_error " '$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback. This may break if $1 contains DOS-style drive
+ # specifications. The fix is not to complicate the expression
+ # below, but for the user to provide a working wine installation
+ # with winepath so that path translation in the cross-to-mingw
+ # case works properly.
+ lt_replace_pathsep_nix_to_dos="s|:|;|g"
+ func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\
+ $SED -e "$lt_replace_pathsep_nix_to_dos"`
+ fi
+ # Now, add the leading and trailing path separators back
+ case "$1" in
+ :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result"
+ ;;
+ esac
+ case "$1" in
+ *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+}
+# end: func_to_host_pathlist
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+ cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+
+ Currently, it simply execs the wrapper *script* "$SHELL $output",
+ but could eventually absorb all of the scripts functionality and
+ exec $objdir/$outputname directly.
+*/
+EOF
+ cat <<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+# define setmode _setmode
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+# include <io.h>
+# define HAVE_SETENV
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+#ifdef _MSC_VER
+# define S_IXUSR _S_IEXEC
+# define stat _stat
+# ifndef _INTPTR_T_DEFINED
+# define intptr_t int
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifdef __CYGWIN__
+# define FOPEN_WB "wb"
+#endif
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#undef LTWRAPPER_DEBUGPRINTF
+#if defined DEBUGWRAPPER
+# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args
+static void
+ltwrapper_debugprintf (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ (void) vfprintf (stderr, fmt, args);
+ va_end (args);
+}
+#else
+# define LTWRAPPER_DEBUGPRINTF(args)
+#endif
+
+const char *program_name = NULL;
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_opt_process_env_set (const char *arg);
+void lt_opt_process_env_prepend (const char *arg);
+void lt_opt_process_env_append (const char *arg);
+int lt_split_name_value (const char *arg, char** name, char** value);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+
+static const char *script_text_part1 =
+EOF
+
+ func_emit_wrapper_part1 yes |
+ $SED -e 's/\([\\"]\)/\\\1/g' \
+ -e 's/^/ "/' -e 's/$/\\n"/'
+ echo ";"
+ cat <<EOF
+
+static const char *script_text_part2 =
+EOF
+ func_emit_wrapper_part2 yes |
+ $SED -e 's/\([\\"]\)/\\\1/g' \
+ -e 's/^/ "/' -e 's/$/\\n"/'
+ echo ";"
+
+ cat <<EOF
+const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ func_to_host_pathlist "$temp_rpath"
+ cat <<EOF
+const char * LIB_PATH_VALUE = "$func_to_host_pathlist_result";
+EOF
+ else
+ cat <<"EOF"
+const char * LIB_PATH_VALUE = "";
+EOF
+ fi
+
+ if test -n "$dllsearchpath"; then
+ func_to_host_pathlist "$dllsearchpath:"
+ cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE = "$func_to_host_pathlist_result";
+EOF
+ else
+ cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE = "";
+EOF
+ fi
+
+ if test "$fast_install" = yes; then
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+ else
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+ fi
+
+
+ cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX "--lt-"
+#define LTWRAPPER_OPTION_PREFIX_LENGTH 5
+
+static const size_t opt_prefix_len = LTWRAPPER_OPTION_PREFIX_LENGTH;
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+
+static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
+
+static const size_t env_set_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 7;
+static const char *env_set_opt = LTWRAPPER_OPTION_PREFIX "env-set";
+ /* argument is putenv-style "foo=bar", value of foo is set to bar */
+
+static const size_t env_prepend_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 11;
+static const char *env_prepend_opt = LTWRAPPER_OPTION_PREFIX "env-prepend";
+ /* argument is putenv-style "foo=bar", new value of foo is bar${foo} */
+
+static const size_t env_append_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 10;
+static const char *env_append_opt = LTWRAPPER_OPTION_PREFIX "env-append";
+ /* argument is putenv-style "foo=bar", new value of foo is ${foo}bar */
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int newargc;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *actual_cwrapper_name;
+ char *target_name;
+ char *lt_argv_zero;
+ intptr_t rval = 127;
+
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ LTWRAPPER_DEBUGPRINTF (("(main) argv[0] : %s\n", argv[0]));
+ LTWRAPPER_DEBUGPRINTF (("(main) program_name : %s\n", program_name));
+
+ /* very simple arg parsing; don't want to rely on getopt */
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], dumpscript_opt) == 0)
+ {
+EOF
+ case "$host" in
+ *mingw* | *cygwin* )
+ # make stdout use "unix" line endings
+ echo " setmode(1,_O_BINARY);"
+ ;;
+ esac
+
+ cat <<"EOF"
+ printf ("%s", script_text_part1);
+ printf ("%s", script_text_part2);
+ return 0;
+ }
+ }
+
+ newargz = XMALLOC (char *, argc + 1);
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
+ lt_fatal ("Couldn't find %s", argv[0]);
+ LTWRAPPER_DEBUGPRINTF (("(main) found exe (before symlink chase) at : %s\n",
+ tmp_pathspec));
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ LTWRAPPER_DEBUGPRINTF (("(main) found exe (after symlink chase) at : %s\n",
+ actual_cwrapper_path));
+ XFREE (tmp_pathspec);
+
+ actual_cwrapper_name = xstrdup( base_name (actual_cwrapper_path));
+ strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+ /* wrapper name transforms */
+ strendzap (actual_cwrapper_name, ".exe");
+ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+ XFREE (actual_cwrapper_name);
+ actual_cwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ /* target_name transforms -- use actual target program name; might have lt- prefix */
+ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+ strendzap (target_name, ".exe");
+ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+ XFREE (target_name);
+ target_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ LTWRAPPER_DEBUGPRINTF (("(main) libtool target name: %s\n",
+ target_name));
+EOF
+
+ cat <<EOF
+ newargz[0] =
+ XMALLOC (char, (strlen (actual_cwrapper_path) +
+ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+ strcpy (newargz[0], actual_cwrapper_path);
+ strcat (newargz[0], "$objdir");
+ strcat (newargz[0], "/");
+EOF
+
+ cat <<"EOF"
+ /* stop here, and copy so we don't have to do this twice */
+ tmp_pathspec = xstrdup (newargz[0]);
+
+ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+ strcat (newargz[0], actual_cwrapper_name);
+
+ /* DO want the lt- prefix here if it exists, so use target_name */
+ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+ XFREE (tmp_pathspec);
+ tmp_pathspec = NULL;
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p;
+ while ((p = strchr (newargz[0], '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE (target_name);
+ XFREE (actual_cwrapper_path);
+ XFREE (actual_cwrapper_name);
+
+ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
+ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+
+ newargc=0;
+ for (i = 1; i < argc; i++)
+ {
+ if (strncmp (argv[i], env_set_opt, env_set_opt_len) == 0)
+ {
+ if (argv[i][env_set_opt_len] == '=')
+ {
+ const char *p = argv[i] + env_set_opt_len + 1;
+ lt_opt_process_env_set (p);
+ }
+ else if (argv[i][env_set_opt_len] == '\0' && i + 1 < argc)
+ {
+ lt_opt_process_env_set (argv[++i]); /* don't copy */
+ }
+ else
+ lt_fatal ("%s missing required argument", env_set_opt);
+ continue;
+ }
+ if (strncmp (argv[i], env_prepend_opt, env_prepend_opt_len) == 0)
+ {
+ if (argv[i][env_prepend_opt_len] == '=')
+ {
+ const char *p = argv[i] + env_prepend_opt_len + 1;
+ lt_opt_process_env_prepend (p);
+ }
+ else if (argv[i][env_prepend_opt_len] == '\0' && i + 1 < argc)
+ {
+ lt_opt_process_env_prepend (argv[++i]); /* don't copy */
+ }
+ else
+ lt_fatal ("%s missing required argument", env_prepend_opt);
+ continue;
+ }
+ if (strncmp (argv[i], env_append_opt, env_append_opt_len) == 0)
+ {
+ if (argv[i][env_append_opt_len] == '=')
+ {
+ const char *p = argv[i] + env_append_opt_len + 1;
+ lt_opt_process_env_append (p);
+ }
+ else if (argv[i][env_append_opt_len] == '\0' && i + 1 < argc)
+ {
+ lt_opt_process_env_append (argv[++i]); /* don't copy */
+ }
+ else
+ lt_fatal ("%s missing required argument", env_append_opt);
+ continue;
+ }
+ if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0)
+ {
+ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+ namespace, but it is not one of the ones we know about and
+ have already dealt with, above (inluding dump-script), then
+ report an error. Otherwise, targets might begin to believe
+ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+ namespace. The first time any user complains about this, we'll
+ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+ or a configure.ac-settable value.
+ */
+ lt_fatal ("Unrecognized option in %s namespace: '%s'",
+ ltwrapper_option_prefix, argv[i]);
+ }
+ /* otherwise ... */
+ newargz[++newargc] = xstrdup (argv[i]);
+ }
+ newargz[++newargc] = NULL;
+
+ LTWRAPPER_DEBUGPRINTF (("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>")));
+ for (i = 0; i < newargc; i++)
+ {
+ LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>")));
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ /* execv doesn't actually work on mingw as expected on unix */
+ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ if (rval == -1)
+ {
+ /* failed to start process */
+ LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno));
+ return 127;
+ }
+ return rval;
+EOF
+ ;;
+ *)
+ cat <<"EOF"
+ execv (lt_argv_zero, newargz);
+ return rval; /* =127, but avoids unused variable warning */
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void *p = (void *) malloc (num);
+ if (!p)
+ lt_fatal ("Memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+ string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable (const char *path)
+{
+ struct stat st;
+
+ LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n",
+ path ? (*path ? path : "EMPTY!") : "NULL!"));
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0)
+ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return 1;
+ else
+ return 0;
+}
+
+int
+make_executable (const char *path)
+{
+ int rval = 0;
+ struct stat st;
+
+ LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n",
+ path ? (*path ? path : "EMPTY!") : "NULL!"));
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+ }
+ return rval;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+ int has_slash = 0;
+ const char *p;
+ const char *p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ int tmp_len;
+ char *concat_name;
+
+ LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n",
+ wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"));
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char *path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char *q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR (*q))
+ break;
+ p_len = q - p;
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen (tmp);
+ concat_name =
+ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name =
+ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen (tmp);
+ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup (pathspec);
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ char *tmp_pathspec = xstrdup (pathspec);
+ char *p;
+ int has_symlinks = 0;
+ while (strlen (tmp_pathspec) && !has_symlinks)
+ {
+ LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n",
+ tmp_pathspec));
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK (s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ p--;
+ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ char *errstr = strerror (errno);
+ lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr);
+ }
+ }
+ XFREE (tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup (pathspec);
+ }
+
+ tmp_pathspec = realpath (pathspec, buf);
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal ("Could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert (str != NULL);
+ assert (pat != NULL);
+
+ len = strlen (str);
+ patlen = strlen (pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp (str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+static void
+lt_error_core (int exit_status, const char *mode,
+ const char *message, va_list ap)
+{
+ fprintf (stderr, "%s: %s: ", program_name, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+ va_end (ap);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+ LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n",
+ (name ? name : "<NULL>"),
+ (value ? value : "<NULL>")));
+ {
+#ifdef HAVE_SETENV
+ /* always make a copy, for consistency with !HAVE_SETENV */
+ char *str = xstrdup (value);
+ setenv (name, str, 1);
+#else
+ int len = strlen (name) + 1 + strlen (value) + 1;
+ char *str = XMALLOC (char, len);
+ sprintf (str, "%s=%s", name, value);
+ if (putenv (str) != EXIT_SUCCESS)
+ {
+ XFREE (str);
+ }
+#endif
+ }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+ char *new_value;
+ if (orig_value && *orig_value)
+ {
+ int orig_value_len = strlen (orig_value);
+ int add_len = strlen (add);
+ new_value = XMALLOC (char, add_len + orig_value_len + 1);
+ if (to_end)
+ {
+ strcpy (new_value, orig_value);
+ strcpy (new_value + orig_value_len, add);
+ }
+ else
+ {
+ strcpy (new_value, add);
+ strcpy (new_value + add_len, orig_value);
+ }
+ }
+ else
+ {
+ new_value = xstrdup (add);
+ }
+ return new_value;
+}
+
+int
+lt_split_name_value (const char *arg, char** name, char** value)
+{
+ const char *p;
+ int len;
+ if (!arg || !*arg)
+ return 1;
+
+ p = strchr (arg, (int)'=');
+
+ if (!p)
+ return 1;
+
+ *value = xstrdup (++p);
+
+ len = strlen (arg) - strlen (*value);
+ *name = XMALLOC (char, len);
+ strncpy (*name, arg, len-1);
+ (*name)[len - 1] = '\0';
+
+ return 0;
+}
+
+void
+lt_opt_process_env_set (const char *arg)
+{
+ char *name = NULL;
+ char *value = NULL;
+
+ if (lt_split_name_value (arg, &name, &value) != 0)
+ {
+ XFREE (name);
+ XFREE (value);
+ lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg);
+ }
+
+ lt_setenv (name, value);
+ XFREE (name);
+ XFREE (value);
+}
+
+void
+lt_opt_process_env_prepend (const char *arg)
+{
+ char *name = NULL;
+ char *value = NULL;
+ char *new_value = NULL;
+
+ if (lt_split_name_value (arg, &name, &value) != 0)
+ {
+ XFREE (name);
+ XFREE (value);
+ lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg);
+ }
+
+ new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ XFREE (name);
+ XFREE (value);
+}
+
+void
+lt_opt_process_env_append (const char *arg)
+{
+ char *name = NULL;
+ char *value = NULL;
+ char *new_value = NULL;
+
+ if (lt_split_name_value (arg, &name, &value) != 0)
+ {
+ XFREE (name);
+ XFREE (value);
+ lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg);
+ }
+
+ new_value = lt_extend_str (getenv (name), value, 1);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ XFREE (name);
+ XFREE (value);
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+ LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+ (name ? name : "<NULL>"),
+ (value ? value : "<NULL>")));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ /* some systems can't cope with a ':'-terminated path #' */
+ int len = strlen (new_value);
+ while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ {
+ new_value[len-1] = '\0';
+ }
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+ LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+ (name ? name : "<NULL>"),
+ (value ? value : "<NULL>")));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_mode_link arg...
+func_mode_link ()
+{
+ $opt_debug
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args=$nonopt
+ base_compile="$nonopt $@"
+ compile_command=$nonopt
+ finalize_command=$nonopt
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+ new_inherited_linker_flags=
+
+ avoid_version=no
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+ weak_libs=
+ single_module="${wl}-single_module"
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ break
+ ;;
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ func_warning "complete static linking is impossible in this configuration"
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ func_quote_for_eval "$arg"
+ qarg=$func_quote_for_eval_unquoted_result
+ func_append libtool_args " $func_quote_for_eval_result"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ func_append compile_command " @OUTPUT@"
+ func_append finalize_command " @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ func_append compile_command " @SYMFILE@"
+ func_append finalize_command " @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ test -f "$arg" \
+ || func_fatal_error "symbol file \`$arg' does not exist"
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ framework)
+ case $host in
+ *-*-darwin*)
+ case "$deplibs " in
+ *" $qarg.ltframework "*) ;;
+ *) deplibs="$deplibs $qarg.ltframework" # this is fixed later
+ ;;
+ esac
+ ;;
+ esac
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat "$save_arg"`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ done
+ else
+ func_fatal_error "link input file \`$arg' does not exist"
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ weak)
+ weak_libs="$weak_libs $arg"
+ prev=
+ continue
+ ;;
+ xcclinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ func_append compile_command " $wl$qarg"
+ func_append finalize_command " $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ # See comment for -static flag below, for more details.
+ func_append compile_command " $link_static_flag"
+ func_append finalize_command " $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ func_fatal_error "more than one -exported-symbols argument is not allowed"
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework)
+ prev=framework
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ func_stripname '-L' '' "$arg"
+ dir=$func_stripname_result
+ if test -z "$dir"; then
+ if test "$#" -gt 0; then
+ func_fatal_error "require no space between \`-L' and \`$1'"
+ else
+ func_fatal_error "need path for \`-L' option"
+ fi
+ fi
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ test -z "$absdir" && \
+ func_fatal_error "cannot determine absolute directory name of \`$dir'"
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ ::) dllsearchpath=$dir;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ deplibs="$deplibs System.ltframework"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test "X$arg" = "X-lc" && continue
+ ;;
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ # Darwin uses the -arch flag to determine output architecture.
+ -model|-arch|-isysroot)
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;;
+ esac
+ continue
+ ;;
+
+ -multi_module)
+ single_module="${wl}-multi_module"
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ func_warning "\`-no-install' is ignored for $host"
+ func_warning "assuming \`-no-fast-install' instead"
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ func_stripname '-R' '' "$arg"
+ dir=$func_stripname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -shared)
+ # The effects of -shared are defined in a previous loop.
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -weak)
+ prev=weak
+ continue
+ ;;
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ arg="$arg $wl$func_quote_for_eval_result"
+ compiler_flags="$compiler_flags $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Wl,*)
+ func_stripname '-Wl,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ arg="$arg $wl$func_quote_for_eval_result"
+ compiler_flags="$compiler_flags $wl$func_quote_for_eval_result"
+ linker_flags="$linker_flags $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # -msg_* for osf cc
+ -msg_*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+ # -r[0-9][0-9]* specifies the processor on the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+ # +DA*, +DD* enable 64-bit mode on the HP compiler
+ # -q* pass through compiler args for the IBM compiler
+ # -m*, -t[45]*, -txscale* pass through architecture-specific
+ # compiler args for GCC
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ compiler_flags="$compiler_flags $arg"
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+ done # argument parsing loop
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prevarg' option requires an argument"
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ func_basename "$output"
+ outputname="$func_basename_result"
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ func_dirname "$output" "/" ""
+ output_objdir="$func_dirname_result$objdir"
+ # Create the object directory.
+ func_mkdir_p "$output_objdir"
+
+ # Determine the type of output
+ case $output in
+ "")
+ func_fatal_help "you must specify an output file"
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if $opt_duplicate_deps ; then
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ libs="$libs $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if $opt_duplicate_compiler_generated_deps; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+
+ case $linkmode in
+ lib)
+ passes="conv dlpreopen link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+
+ for pass in $passes; do
+ # The preopen pass in lib mode reverses $deplibs; put it back here
+ # so that -L comes before libs that need it for instance...
+ if test "$linkmode,$pass" = "lib,link"; then
+ ## FIXME: Find the place where the list is rebuilt in the wrong
+ ## order, and fix it there properly
+ tmp_deplibs=
+ for deplib in $deplibs; do
+ tmp_deplibs="$deplib $tmp_deplibs"
+ done
+ deplibs="$tmp_deplibs"
+ fi
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link)
+ libs="$deplibs %DEPLIBS%"
+ test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+ ;;
+ esac
+ fi
+ if test "$linkmode,$pass" = "lib,dlpreopen"; then
+ # Collect and forward deplibs of preopened libtool libs
+ for lib in $dlprefiles; do
+ # Ignore non-libtool-libs
+ dependency_libs=
+ case $lib in
+ *.la) func_source "$lib" ;;
+ esac
+
+ # Collect preopened libtool deplibs, except any this library
+ # has declared as weak libs
+ for deplib in $dependency_libs; do
+ deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"`
+ case " $weak_libs " in
+ *" $deplib_base "*) ;;
+ *) deplibs="$deplibs $deplib" ;;
+ esac
+ done
+ done
+ libs="$dlprefiles"
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags $deplib"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ func_warning "\`-l' is ignored for archives/objects"
+ continue
+ fi
+ func_stripname '-l' '' "$deplib"
+ name=$func_stripname_result
+ if test "$linkmode" = lib; then
+ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+ else
+ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+ fi
+ for searchdir in $searchdirs; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if func_lalib_p "$lib"; then
+ library_names=
+ old_library=
+ func_source "$lib"
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ *.ltframework)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ *)
+ func_warning "\`-L' is ignored for archives/objects"
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ func_stripname '-R' '' "$deplib"
+ dir=$func_stripname_result
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ # Linking convenience modules into shared libraries is allowed,
+ # but linking other static libraries is non-portable.
+ case " $dlpreconveniencelibs " in
+ *" $deplib "*) ;;
+ *)
+ valid_a_lib=no
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=yes
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=yes
+ ;;
+ esac
+ if test "$valid_a_lib" != yes; then
+ $ECHO
+ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+ $ECHO "*** I have the capability to make that library automatically link in when"
+ $ECHO "*** you link to this library. But I can only do this if you have a"
+ $ECHO "*** shared version of the library, which you do not appear to have"
+ $ECHO "*** because the file extensions .$libext of this argument makes me believe"
+ $ECHO "*** that it is just a static archive that I should not use here."
+ else
+ $ECHO
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ ;;
+ esac
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+ fi
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$lib" \
+ || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ inherited_linker_flags=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ func_source "$lib"
+
+ # Convert "-framework foo" to "foo.ltframework"
+ if test -n "$inherited_linker_flags"; then
+ tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'`
+ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+ case " $new_inherited_linker_flags " in
+ *" $tmp_inherited_linker_flag "*) ;;
+ *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";;
+ esac
+ done
+ fi
+ dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ func_fatal_error "\`$lib' is not a convenience library"
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+ fi
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ dlprefiles="$dlprefiles $lib $dependency_libs"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ func_warning "cannot determine absolute directory name of \`$ladir'"
+ func_warning "passing it literally to the linker, although it might fail"
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ func_basename "$lib"
+ laname="$func_basename_result"
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ func_warning "library \`$lib' was moved."
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir="$ladir"
+ absdir="$abs_ladir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi
+ fi # $installed = yes
+ func_stripname 'lib' '.la' "$laname"
+ name=$func_stripname_result
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir" && test "$linkmode" = prog; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { { test "$prefer_static_libs" = no ||
+ test "$prefer_static_libs,$installed" = "built,yes"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath:" in
+ *"$absdir:"*) ;;
+ *) temp_rpath="$temp_rpath$absdir:" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test "$use_static_libs" = built && test "$installed" = yes; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ case $host in
+ *cygwin* | *mingw* | *cegcc*)
+ # No point in relinking DLLs because paths are not encoded
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=no
+ ;;
+ *)
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+ ;;
+ esac
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some
+ # systems (darwin). Don't bleat about dlopened modules though!
+ dlopenmodule=""
+ for dlpremoduletest in $dlprefiles; do
+ if test "X$dlpremoduletest" = "X$lib"; then
+ dlopenmodule="$dlpremoduletest"
+ break
+ fi
+ done
+ if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+ $ECHO
+ if test "$linkmode" = prog; then
+ $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $ECHO "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw* | *cegcc*)
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ func_basename "$soroot"
+ soname="$func_basename_result"
+ func_stripname 'lib' '.dll' "$soname"
+ newlib=libimp-$func_stripname_result.a
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ func_verbose "extracting exported symbol list from \`$soname'"
+ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ func_verbose "generating import library for \`$soname'"
+ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a (non-dlopened) module then we can not
+ # link against it, someone is ignoring the earlier warnings
+ if /usr/bin/file -L $add 2> /dev/null |
+ $GREP ": [^:]* bundle" >/dev/null ; then
+ if test "X$dlopenmodule" != "X$lib"; then
+ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ $ECHO
+ $ECHO "*** And there doesn't seem to be a static archive available"
+ $ECHO "*** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ elif test -n "$old_library"; then
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ func_fatal_configuration "unsupported hardcode properties"
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes &&
+ test "$hardcode_minus_L" != yes &&
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ $ECHO
+ $ECHO "*** Warning: This system can not link to static lib archive $lib."
+ $ECHO "*** I have the capability to make that library automatically link in when"
+ $ECHO "*** you link to this library. But I can only do this if you have a"
+ $ECHO "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ $ECHO "*** But as you try to build a module library, libtool will still create "
+ $ECHO "*** a static module, that should work as long as the dlopening application"
+ $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ $ECHO
+ $ECHO "*** However, this would only work if libtool was able to extract symbol"
+ $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $ECHO "*** not find such a program. So, this module is probably useless."
+ $ECHO "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) func_stripname '-R' '' "$libdir"
+ temp_xrpath=$func_stripname_result
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ path=
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ func_dirname "$deplib" "" "."
+ dir="$func_dirname_result"
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ func_warning "cannot determine absolute directory name of \`$dir'"
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if $GREP "^installed=no" $deplib > /dev/null; then
+ case $host in
+ *-*-darwin*)
+ depdepl=
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$absdir/$objdir/$depdepl" ; then
+ depdepl="$absdir/$objdir/$depdepl"
+ darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -z "$darwin_install_name"; then
+ darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ fi
+ compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+ linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}"
+ path=
+ fi
+ fi
+ ;;
+ *)
+ path="-L$absdir/$objdir"
+ ;;
+ esac
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ test "$absdir" != "$libdir" && \
+ func_warning "\`$deplib' seems to be moved"
+
+ path="-L$absdir"
+ fi
+ ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test "$pass" = link; then
+ if test "$linkmode" = "prog"; then
+ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+ fi
+ fi
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ tmp_libs="$tmp_libs $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ fi
+ if test "$linkmode" = prog || test "$linkmode" = lib; then
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for archives"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for archives" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for archives"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for archives"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for archives"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for archives"
+
+ test -n "$export_symbols$export_symbols_regex" && \
+ func_warning "\`-export-symbols' is ignored for archives"
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ func_stripname 'lib' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ test "$module" = no && \
+ func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ func_stripname '' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ func_stripname '' '.la' "$outputname"
+ libname=$func_stripname_result
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+ else
+ $ECHO
+ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+ $ECHO "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ test "$dlself" != no && \
+ func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+ set dummy $rpath
+ shift
+ test "$#" -gt 1 && \
+ func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+ install_libdir="$1"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for convenience libraries"
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ shift
+ IFS="$save_ifs"
+
+ test -n "$7" && \
+ func_fatal_help "too many parameters to \`-version-info'"
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$1"
+ number_minor="$2"
+ number_revision="$3"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ darwin|linux|osf|windows|none)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_minor"
+ lt_irix_increment=no
+ ;;
+ *)
+ func_fatal_configuration "$modename: unknown library version type \`$version_type'"
+ ;;
+ esac
+ ;;
+ no)
+ current="$1"
+ revision="$2"
+ age="$3"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "CURRENT \`$current' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "REVISION \`$revision' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "AGE \`$age' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ func_error "AGE \`$age' is greater than the current interface number \`$current'"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ func_arith $current + 1
+ minor_current=$func_arith_result
+ xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ irix | nonstopux)
+ if test "X$lt_irix_increment" = "Xno"; then
+ func_arith $current - $age
+ else
+ func_arith $current - $age + 1
+ fi
+ major=$func_arith_result
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ func_arith $revision - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ func_arith $current - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ qnx)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+
+ *)
+ func_fatal_configuration "unknown library version type \`$version_type'"
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ func_warning "undefined symbols not allowed in $host shared libraries"
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+
+ fi
+
+ func_generate_dlsyms "$libname" "$libname" "yes"
+ libobjs="$libobjs $symfileobj"
+ test "X$libobjs" = "X " && libobjs=
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$ECHO "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext | *.gcno)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if test "X$precious_files_regex" != "X"; then
+ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ test -n "$removelist" && \
+ func_show_eval "${RM}r \$removelist"
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"`
+ # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"`
+ # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs System.ltframework"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $opt_dry_run || $RM conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $ECHO
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ $ECHO "*** I have the capability to make that library automatically link in when"
+ $ECHO "*** you link to this library. But I can only do this if you have a"
+ $ECHO "*** shared version of the library, which I believe you do not have"
+ $ECHO "*** because a test_compile did reveal that the linker did not use it for"
+ $ECHO "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ ;;
+ *)
+ newdeplibs="$newdeplibs $i"
+ ;;
+ esac
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $ECHO
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ $ECHO "*** I have the capability to make that library automatically link in when"
+ $ECHO "*** you link to this library. But I can only do this if you have a"
+ $ECHO "*** shared version of the library, which you do not appear to have"
+ $ECHO "*** because a test_compile did reveal that the linker did not use this one"
+ $ECHO "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ $ECHO
+ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
+ $ECHO "*** make it link in! You will probably need to install it or some"
+ $ECHO "*** library that it depends on before this library will be fully"
+ $ECHO "*** functional. Installing it before continuing would be even better."
+ fi
+ ;;
+ *)
+ newdeplibs="$newdeplibs $i"
+ ;;
+ esac
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method; shift
+ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null |
+ $GREP " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+ $SED -e 10q |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $ECHO
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ $ECHO "*** I have the capability to make that library automatically link in when"
+ $ECHO "*** you link to this library. But I can only do this if you have a"
+ $ECHO "*** shared version of the library, which you do not appear to have"
+ $ECHO "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \
+ $EGREP "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $ECHO
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ $ECHO "*** I have the capability to make that library automatically link in when"
+ $ECHO "*** you link to this library. But I can only do this if you have a"
+ $ECHO "*** shared version of the library, which you do not appear to have"
+ $ECHO "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \
+ -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"`
+ done
+ fi
+ if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' |
+ $GREP . >/dev/null; then
+ $ECHO
+ if test "X$deplibs_check_method" = "Xnone"; then
+ $ECHO "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ $ECHO "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ $ECHO "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ fi
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library with the System framework
+ newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ $ECHO
+ $ECHO "*** Warning: libtool could not satisfy all declared inter-library"
+ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
+ $ECHO "*** a static module, that should work as long as the dlopening"
+ $ECHO "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ $ECHO
+ $ECHO "*** However, this would only work if libtool was able to extract symbol"
+ $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $ECHO "*** not find such a program. So, this module is probably useless."
+ $ECHO "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ $ECHO "*** The inter-library dependencies that have been dropped here will be"
+ $ECHO "*** automatically added whenever a program is linked with this library"
+ $ECHO "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ $ECHO
+ $ECHO "*** Since this library must not contain undefined symbols,"
+ $ECHO "*** because either the platform does not support them or"
+ $ECHO "*** it was explicitly requested with -no-undefined,"
+ $ECHO "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ case $host in
+ *-*-darwin*)
+ newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+ new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+ deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ deplibs="$new_libs"
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ if test -n "$hardcode_libdir_flag_spec_ld"; then
+ eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+ else
+ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+ fi
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ linknames=
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ test "X$libobjs" = "X " && libobjs=
+
+ delfiles=
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+ export_symbols="$output_objdir/$libname.uexp"
+ delfiles="$delfiles $export_symbols"
+ fi
+
+ orig_export_symbols=
+ case $host_os in
+ cygwin* | mingw* | cegcc*)
+ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+ # exporting using user supplied symfile
+ if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+ # and it's NOT already a .def file. Must figure out
+ # which of the given symbols are data symbols and tag
+ # them as such. So, trigger use of export_symbols_cmds.
+ # export_symbols gets reassigned inside the "prepare
+ # the list of exported symbols" if statement, so the
+ # include_expsyms logic still works.
+ orig_export_symbols="$export_symbols"
+ export_symbols=
+ always_export_symbols=yes
+ fi
+ fi
+ ;;
+ esac
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ func_len " $cmd"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ func_show_eval "$cmd" 'exit $?'
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ func_verbose "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ tmp_deplibs="$tmp_deplibs $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec" &&
+ test "$compiler_needs_object" = yes &&
+ test -z "$libobjs"; then
+ # extract the archives, so we have objects to list.
+ # TODO: could optimize this to just extract one archive.
+ whole_archive_flag_spec=
+ fi
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ else
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ libobjs="$libobjs $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" &&
+ func_len " $test_cmds" &&
+ len=$func_len_result &&
+ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise
+ # or, if using GNU ld and skipped_export is not :, use a linker
+ # script.
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ output_la=`$ECHO "X$output" | $Xsed -e "$basename"`
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ last_robj=
+ k=1
+
+ if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+ output=${output_objdir}/${output_la}.lnkscript
+ func_verbose "creating GNU ld script: $output"
+ $ECHO 'INPUT (' > $output
+ for obj in $save_libobjs
+ do
+ $ECHO "$obj" >> $output
+ done
+ $ECHO ')' >> $output
+ delfiles="$delfiles $output"
+ elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+ output=${output_objdir}/${output_la}.lnk
+ func_verbose "creating linker input file list: $output"
+ : > $output
+ set x $save_libobjs
+ shift
+ firstobj=
+ if test "$compiler_needs_object" = yes; then
+ firstobj="$1 "
+ shift
+ fi
+ for obj
+ do
+ $ECHO "$obj" >> $output
+ done
+ delfiles="$delfiles $output"
+ output=$firstobj\"$file_list_spec$output\"
+ else
+ if test -n "$save_libobjs"; then
+ func_verbose "creating reloadable object files..."
+ output=$output_objdir/$output_la-${k}.$objext
+ eval test_cmds=\"$reload_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ if test "X$objlist" = X ||
+ test "$len" -lt "$max_cmd_len"; then
+ func_append objlist " $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-${k}.$objext
+ func_arith $k + 1
+ k=$func_arith_result
+ output=$output_objdir/$output_la-${k}.$objext
+ objlist=$obj
+ func_len " $last_robj"
+ func_arith $len0 + $func_len_result
+ len=$func_arith_result
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+ fi
+ delfiles="$delfiles $output"
+
+ else
+ output=
+ fi
+
+ if ${skipped_export-false}; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ fi
+
+ test -n "$save_libobjs" &&
+ func_verbose "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+
+ if ${skipped_export-false}; then
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+ fi
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+ fi
+
+ if test -n "$delfiles"; then
+ # Append the command to remove temporary files to $cmds.
+ eval cmds=\"\$cmds~\$RM $delfiles\"
+ fi
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ libobjs="$libobjs $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for objects"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for objects" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for objects"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for objects"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for objects"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for objects"
+
+ case $output in
+ *.lo)
+ test -n "$objs$old_deplibs" && \
+ func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+ libobj=$output
+ func_lo2o "$libobj"
+ obj=$func_lo2o_result
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $opt_dry_run || $RM $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec and hope we can get by with
+ # turning comma into space..
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+ reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'`
+ else
+ gentop="$output_objdir/${obj}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+ fi
+
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result.exe;;
+ esac
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for programs"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for programs"
+
+ test "$preload" = yes \
+ && test "$dlopen_support" = unknown \
+ && test "$dlopen_self" = unknown \
+ && test "$dlopen_self_static" = unknown && \
+ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
+ finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ case $host in
+ *-*-darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ # But is supposedly fixed on 10.4 or later (yay!).
+ if test "$tagname" = CXX ; then
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[0123])
+ compile_command="$compile_command ${wl}-bind_at_load"
+ finalize_command="$finalize_command ${wl}-bind_at_load"
+ ;;
+ esac
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+ finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ compile_deplibs="$new_libs"
+
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ ::) dllsearchpath=$libdir;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ fi
+
+ func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+ # template prelinking step
+ if test -n "$prelink_cmds"; then
+ func_execute_cmds "$prelink_cmds" 'exit $?'
+ fi
+
+ wrappers_required=yes
+ case $host in
+ *cygwin* | *mingw* )
+ if test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ *cegcc)
+ # Disable wrappers for cegcc, we are cross compiling anyway.
+ wrappers_required=no
+ ;;
+ *)
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ esac
+ if test "$wrappers_required" = no; then
+ # Replace the output file specification.
+ compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ exit_status=0
+ func_show_eval "$link_command" 'exit_status=$?'
+
+ # Delete the generated files.
+ if test -f "$output_objdir/${outputname}S.${objext}"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+ fi
+
+ exit $exit_status
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $opt_dry_run || $RM $output
+ # Link the executable and exit
+ func_show_eval "$link_command" 'exit $?'
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "\`$output' will be relinked during installation"
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ func_show_eval "$link_command" 'exit $?'
+
+ # Now create the wrapper script.
+ func_verbose "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Quote $ECHO for shipping.
+ if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then
+ case $progpath in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
+ esac
+ qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"`
+ else
+ qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if not in dry run mode.
+ $opt_dry_run || {
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ func_stripname '' '.exe' "$outputname"
+ outputname=$func_stripname_result ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ func_dirname_and_basename "$output" "" "."
+ output_name=$func_basename_result
+ output_path=$func_dirname_result
+ cwrappersource="$output_path/$objdir/lt-$output_name.c"
+ cwrapper="$output_path/$output_name.exe"
+ $RM $cwrappersource $cwrapper
+ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_cwrapperexe_src > $cwrappersource
+
+ # The wrapper executable is built using the $host compiler,
+ # because it contains $host paths and files. If cross-
+ # compiling, it, like the target executable, must be
+ # executed on the $host or under an emulation environment.
+ $opt_dry_run || {
+ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+ $STRIP $cwrapper
+ }
+
+ # Now, create the wrapper script for func_source use:
+ func_ltwrapper_scriptname $cwrapper
+ $RM $func_ltwrapper_scriptname_result
+ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+ $opt_dry_run || {
+ # note: this script will not be executed, so do not chmod.
+ if test "x$build" = "x$host" ; then
+ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+ else
+ func_emit_wrapper no > $func_ltwrapper_scriptname_result
+ fi
+ }
+ ;;
+ * )
+ $RM $output
+ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_wrapper no > $output
+ chmod +x $output
+ ;;
+ esac
+ }
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ if test "$preload" = yes && test -f "$symfileobj"; then
+ oldobjs="$oldobjs $symfileobj"
+ fi
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $addlibs
+ oldobjs="$oldobjs $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ oldobjs="$oldobjs $func_extract_archives_result"
+ fi
+
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ func_basename "$obj"
+ $ECHO "$func_basename_result"
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $ECHO "copying selected object files to avoid basename conflicts..."
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+ func_mkdir_p "$gentop"
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ func_basename "$obj"
+ objbase="$func_basename_result"
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ func_arith $counter + 1
+ counter=$func_arith_result
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ oldobjs="$oldobjs $gentop/$newobj"
+ ;;
+ *) oldobjs="$oldobjs $obj" ;;
+ esac
+ done
+ fi
+ eval cmds=\"$old_archive_cmds\"
+
+ func_len " $cmds"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ func_verbose "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ oldobjs=
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ eval test_cmds=\"$old_archive_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+ for obj in $save_oldobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ func_append objlist " $obj"
+ if test "$len" -lt "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ len=$len0
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ func_execute_cmds "$cmds" 'exit $?'
+ done
+
+ test -n "$generated" && \
+ func_show_eval "${RM}r$generated"
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ func_verbose "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+
+ # Only create the output if not a dry run.
+ $opt_dry_run || {
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ func_basename "$deplib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+
+ for lib in $dlfiles; do
+ case $lib in
+ *.la)
+ func_basename "$lib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ newdlfiles="$newdlfiles $libdir/$name"
+ ;;
+ *) newdlfiles="$newdlfiles $lib" ;;
+ esac
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ *.la)
+ # Only pass preopened files to the pseudo-archive (for
+ # eventual linking with the app. that links it) if we
+ # didn't already link the preopened objects directly into
+ # the library:
+ func_basename "$lib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ ;;
+ esac
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlfiles="$newdlfiles $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlprefiles="$newdlprefiles $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $RM $output
+ # place dlname in correct position for cygwin
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+ esac
+ $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $ECHO >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ }
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+}
+
+{ test "$mode" = link || test "$mode" = relink; } &&
+ func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+ $opt_debug
+ RM="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) RM="$RM $arg"; rmforce=yes ;;
+ -*) RM="$RM $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ test -z "$RM" && \
+ func_fatal_help "you must specify an RM program"
+
+ rmdirs=
+
+ origobjdir="$objdir"
+ for file in $files; do
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ if test "X$dir" = X.; then
+ objdir="$origobjdir"
+ else
+ objdir="$dir/$origobjdir"
+ fi
+ func_basename "$file"
+ name="$func_basename_result"
+ test "$mode" = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test "$mode" = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if { test -L "$file"; } >/dev/null 2>&1 ||
+ { test -h "$file"; } >/dev/null 2>&1 ||
+ test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if func_lalib_p "$file"; then
+ func_source $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+
+ case "$mode" in
+ clean)
+ case " $library_names " in
+ # " " in the beginning catches empty $dlname
+ *" $dlname "*) ;;
+ *) rmfiles="$rmfiles $objdir/$dlname" ;;
+ esac
+ test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if func_lalib_p "$file"; then
+
+ # Read the .lo file
+ func_source $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" &&
+ test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" &&
+ test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ func_stripname '' '.exe' "$name"
+ noexename=$func_stripname_result
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ rmfiles="$rmfiles $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if func_ltwrapper_p "$file"; then
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ relink_command=
+ func_source $func_ltwrapper_scriptname_result
+ rmfiles="$rmfiles $func_ltwrapper_scriptname_result"
+ else
+ relink_command=
+ func_source $dir/$noexename
+ fi
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ func_show_eval "$RM $rmfiles" 'exit_status=1'
+ done
+ objdir="$origobjdir"
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ func_show_eval "rmdir $dir >/dev/null 2>&1"
+ fi
+ done
+
+ exit $exit_status
+}
+
+{ test "$mode" = uninstall || test "$mode" = clean; } &&
+ func_mode_uninstall ${1+"$@"}
+
+test -z "$mode" && {
+ help="$generic_help"
+ func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+ func_fatal_help "invalid operation mode \`$mode'"
+
+if test -n "$exec_cmd"; then
+ eval exec "$exec_cmd"
+ exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/m4/ax_check_compiler_flags.m4 b/m4/ax_check_compiler_flags.m4
new file mode 100644
index 0000000..05e5c3b
--- /dev/null
+++ b/m4/ax_check_compiler_flags.m4
@@ -0,0 +1,78 @@
+# ===========================================================================
+# http://autoconf-archive.cryp.to/ax_check_compiler_flags.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_COMPILER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE])
+#
+# DESCRIPTION
+#
+# Check whether the given compiler FLAGS work with the current language's
+# compiler, or whether they give an error. (Warnings, however, are
+# ignored.)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# LAST MODIFICATION
+#
+# 2008-04-12
+#
+# COPYLEFT
+#
+# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+# Copyright (c) 2008 Matteo Frigo
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Macro Archive. When you make and
+# distribute a modified version of the Autoconf Macro, you may extend this
+# special exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AX_CHECK_COMPILER_FLAGS],
+[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX
+AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1])
+dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname:
+AS_LITERAL_IF([$1],
+ [AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1), [
+ ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
+ _AC_LANG_PREFIX[]FLAGS="$1"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+ AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes,
+ AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no)
+ _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])],
+ [ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
+ _AC_LANG_PREFIX[]FLAGS="$1"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+ eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes,
+ eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no)
+ _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])
+eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)
+AC_MSG_RESULT($ax_check_compiler_flags)
+if test "x$ax_check_compiler_flags" = xyes; then
+ m4_default([$2], :)
+else
+ m4_default([$3], :)
+fi
+])dnl AX_CHECK_COMPILER_FLAGS
diff --git a/m4/ax_ext.m4 b/m4/ax_ext.m4
new file mode 100644
index 0000000..41536f7
--- /dev/null
+++ b/m4/ax_ext.m4
@@ -0,0 +1,122 @@
+# ===========================================================================
+# http://autoconf-archive.cryp.to/ax_ext.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_EXT
+#
+# DESCRIPTION
+#
+# Find supported SIMD extensions by requesting cpuid. When an SIMD
+# extension is found, the -m"simdextensionname" is added to SIMD_FLAGS
+# (only if compilator support it) (ie : if "sse2" is available "-msse2" is
+# added to SIMD_FLAGS)
+#
+# This macro calls:
+#
+# AC_SUBST(SIMD_FLAGS)
+#
+# And defines:
+#
+# HAVE_MMX / HAVE_SSE / HAVE_SSE2 / HAVE_SSE3 / HAVE_SSSE3
+#
+# LAST MODIFICATION
+#
+# 2008-04-12
+# 2009-04-23 Mark Asbach <markasbach@users.sourceforge.net<
+# Renamed cache variables so they adhere naming convention
+# Corrected M4 quoting for AX_CHECK_COMPILER_FLAGS
+#
+# COPYLEFT
+#
+# Copyright (c) 2008 Christophe Tournayre <turn3r@users.sourceforge.net>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved.
+
+AC_DEFUN([AX_EXT],
+[
+ AC_REQUIRE([AX_GCC_X86_CPUID])
+
+ AX_GCC_X86_CPUID([0x00000001])
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ ecx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 3`
+ edx=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 4`
+ fi
+
+ AC_CACHE_CHECK([whether mmx is supported], [ax_cv_have_mmx_ext],
+ [
+ ax_cv_have_mmx_ext=no
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ if test "$((0x$edx>>23&0x01))" = 1; then
+ ax_cv_have_mmx_ext=yes
+ fi
+ fi
+ ])
+
+ AC_CACHE_CHECK([whether sse is supported], [ax_cv_have_sse_ext],
+ [
+ ax_cv_have_sse_ext=no
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ if test "$((0x$edx>>25&0x01))" = 1; then
+ ax_cv_have_sse_ext=yes
+ fi
+ fi
+ ])
+
+ AC_CACHE_CHECK([whether sse2 is supported], [ax_cv_have_sse2_ext],
+ [
+ ax_cv_have_sse2_ext=no
+ if test "$((0x$edx>>26&0x01))" = 1; then
+ ax_cv_have_sse2_ext=yes
+ fi
+ ])
+
+ AC_CACHE_CHECK([whether sse3 is supported], [ax_cv_have_sse3_ext],
+ [
+ ax_cv_have_sse3_ext=no
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ if test "$((0x$ecx&0x01))" = 1; then
+ ax_cv_have_sse3_ext=yes
+ fi
+ fi
+ ])
+
+ AC_CACHE_CHECK([whether ssse3 is supported], [ax_cv_have_ssse3_ext],
+ [
+ ax_cv_have_ssse3_ext=no
+ if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then
+ if test "$((0x$ecx>>9&0x01))" = 1; then
+ ax_cv_have_ssse3_ext=yes
+ fi
+ fi
+ ])
+
+ if test "$ax_cv_have_mmx_ext" = yes; then
+ AC_DEFINE(HAVE_MMX,,[Support mmx instructions])
+ AX_CHECK_COMPILER_FLAGS([-mmmx], [SIMD_FLAGS="$SIMD_FLAGS -mmmx"], [])
+ fi
+
+ if test "$ax_cv_have_sse_ext" = yes; then
+ AC_DEFINE(HAVE_SSE,,[Support SSE (Streaming SIMD Extensions) instructions])
+ AX_CHECK_COMPILER_FLAGS([-msse], [SIMD_FLAGS="$SIMD_FLAGS -msse"], [])
+ fi
+
+ if test "$ax_cv_have_sse2_ext" = yes; then
+ AC_DEFINE(HAVE_SSE2,,[Support SSE2 (Streaming SIMD Extensions 2) instructions])
+ AX_CHECK_COMPILER_FLAGS([-msse2], [SIMD_FLAGS="$SIMD_FLAGS -msse2"], [])
+ fi
+
+ if test "$ax_cv_have_sse3_ext" = yes; then
+ AC_DEFINE(HAVE_SSE3,,[Support SSE3 (Streaming SIMD Extensions 3) instructions])
+ AX_CHECK_COMPILER_FLAGS([-msse3], [SIMD_FLAGS="$SIMD_FLAGS -msse3"], [])
+ fi
+
+ if test "$ax_cv_have_ssse3_ext" = yes; then
+ AC_DEFINE(HAVE_SSSE3,,[Support SSSE3 (Supplemental Streaming SIMD Extensions 3) instructions])
+ fi
+
+ AC_SUBST(SIMD_FLAGS)
+])
diff --git a/m4/ax_gcc_x86_cpuid.m4 b/m4/ax_gcc_x86_cpuid.m4
new file mode 100644
index 0000000..e9231b8
--- /dev/null
+++ b/m4/ax_gcc_x86_cpuid.m4
@@ -0,0 +1,65 @@
+dnl @synopsis AX_GCC_X86_CPUID(OP)
+dnl @summary run x86 cpuid instruction OP using gcc inline assembler
+dnl @category Misc
+dnl
+dnl On Pentium and later x86 processors, with gcc or a compiler that
+dnl has a compatible syntax for inline assembly instructions, run
+dnl a small program that executes the cpuid instruction with
+dnl input OP. This can be used to detect the CPU type.
+dnl
+dnl On output, the values of the eax, ebx, ecx, and edx registers
+dnl are stored as hexadecimal strings as "eax:ebx:ecx:edx" in
+dnl the cache variable ax_cv_gcc_x86_cpuid_OP.
+dnl
+dnl If the cpuid instruction fails (because you are running a cross-compiler,
+dnl or because you are not using gcc, or because you are on a processor
+dnl that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP is set
+dnl to the string "unknown".
+dnl
+dnl This macro mainly exists to be used in AX_GCC_ARCHFLAG.
+dnl
+dnl @version 2008-12-06
+dnl @license GPLWithACException
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Matteo Frigo.
+AC_DEFUN([AX_GCC_X86_CPUID],
+[AC_REQUIRE([AC_PROG_CC])
+AC_LANG_PUSH([C])
+AC_CACHE_CHECK([for x86 cpuid $1 output], [ax_cv_gcc_x86_cpuid_$1],
+ [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <stdio.h>], [
+ int op = $1, eax, ebx, ecx, edx;
+ FILE *f;
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
+ __asm__("push %%rbx\n\t"
+ "cpuid\n\t"
+ "pop %%rbx"
+ : "=a" (eax), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ __asm__("push %%rbx\n\t"
+ "cpuid\n\t"
+ "mov %%rbx, %%rax\n\t"
+ "pop %%rbx"
+ : "=a" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+#else
+ __asm__("push %%ebx\n\t"
+ "cpuid\n\t"
+ "pop %%ebx"
+ : "=a" (eax), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ __asm__("push %%ebx\n\t"
+ "cpuid\n\t"
+ "mov %%ebx, %%eax\n\t"
+ "pop %%ebx"
+ : "=a" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+#endif
+ f = fopen("conftest_cpuid", "w"); if (!f) return 1;
+ fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx);
+ fclose(f);
+ return 0;
+])],
+ [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid],
+ [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid],
+ [ax_cv_gcc_x86_cpuid_$1=unknown])])
+AC_LANG_POP([C])
+])
diff --git a/m4/libtool.m4 b/m4/libtool.m4
new file mode 100644
index 0000000..a3fee53
--- /dev/null
+++ b/m4/libtool.m4
@@ -0,0 +1,7377 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 56 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+_LT_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "X$<var>" | $Xsed -e "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Fix-up fallback echo if it was mangled by the above quoting rules.
+case \$lt_ECHO in
+*'\\\[$]0 --fallback-echo"')dnl "
+ lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\`
+ ;;
+esac
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+cat >"$CONFIG_LT" <<_LTEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate a libtool stub with the current configuration.
+
+lt_cl_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AS_SHELL_SANITIZE
+_AS_PREPARE
+
+exec AS_MESSAGE_FD>&1
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+if test "$no_create" != yes; then
+ lt_cl_success=:
+ test "$silent" = yes &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+ exec AS_MESSAGE_LOG_FD>/dev/null
+ $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+ exec AS_MESSAGE_LOG_FD>>config.log
+ $lt_cl_success || AS_EXIT(1)
+fi
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ _LT_PROG_XSI_SHELLFNS
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS="$save_LDFLAGS"
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES
+# --------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=echo
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ m4_if([$1], [CXX],
+[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX
+# -----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+ [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+ [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_SHELL_INIT
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[_LT_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$lt_ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+ ;;
+esac
+
+ECHO=${lt_ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X[$]1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
+ # Yippee, $ECHO works!
+ :
+else
+ # Restart under the correct shell.
+ exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<_LT_EOF
+[$]*
+_LT_EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$lt_ECHO"; then
+ if test "X${echo_test_string+set}" != Xset; then
+ # find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
+ { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
+ then
+ break
+ fi
+ done
+ fi
+
+ if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+ else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ ECHO="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$ECHO" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ ECHO='print -r'
+ elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+ else
+ # Try using printf.
+ ECHO='printf %s\n'
+ if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+ if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "[$]0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ ECHO=echo
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+lt_ECHO=$ECHO
+if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+ lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(lt_ECHO)
+])
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1],
+ [An echo program that does not interpret backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[AC_CHECK_TOOL(AR, ar, false)
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1])
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
+ = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+ [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+ test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[123]]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # Some binutils ld are patched to set DT_RUNPATH
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+ [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_DECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method == "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :)
+ AC_SUBST([DUMPBIN])
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC*)
+ # IBM XL 8.0 on PPC
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd* | netbsdelf*-gnu)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl*)
+ # IBM XL C 8.0/Fortran 10.1 on PPC
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Sun\ F*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ linux* | k*bsd*-gnu)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ freebsd1*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ AC_LINK_IFELSE(int foo(void) {},
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ )
+ LDFLAGS="$save_LDFLAGS"
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)])
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
+ [[If ld is used when linking, flag to hardcode $libdir into a binary
+ during linking. This must work even if $libdir does not exist]])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [fix_srcfile_path], [1],
+ [Fix the shell variable $srcfile for the compiler])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report which library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_PROG_CXX
+# ------------
+# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++
+# compiler, we have our own version here.
+m4_defun([_LT_PROG_CXX],
+[
+pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes])
+AC_PROG_CXX
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_CXX
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_CXX], [])
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[AC_REQUIRE([_LT_PROG_CXX])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd[[12]]*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ gnu*)
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 will use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ ;;
+ xl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='echo'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=echo
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='echo'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)="$GXX"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_PROG_F77
+# ------------
+# Since AC_PROG_F77 is broken, in that it returns the empty string
+# if there is no fortran compiler, we have our own version here.
+m4_defun([_LT_PROG_F77],
+[
+pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes])
+AC_PROG_F77
+if test -z "$F77" || test "X$F77" = "Xno"; then
+ _lt_disable_F77=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_F77
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_F77], [])
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_REQUIRE([_LT_PROG_F77])dnl
+AC_LANG_PUSH(Fortran 77)
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ CC=${F77-"f77"}
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$G77"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_PROG_FC
+# -----------
+# Since AC_PROG_FC is broken, in that it returns the empty string
+# if there is no fortran compiler, we have our own version here.
+m4_defun([_LT_PROG_FC],
+[
+pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes])
+AC_PROG_FC
+if test -z "$FC" || test "X$FC" = "Xno"; then
+ _lt_disable_FC=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_FC
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_FC], [])
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_REQUIRE([_LT_PROG_FC])dnl
+AC_LANG_PUSH(Fortran)
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ CC=${FC-"f95"}
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_XSI_SHELLFNS
+# ---------------------
+# Bourne and XSI compatible variants of some useful shell functions.
+m4_defun([_LT_PROG_XSI_SHELLFNS],
+[case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=$(( $[*] ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=${#1}
+}
+
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+}
+
+dnl func_dirname_and_basename
+dnl A portable version of this function is already defined in general.m4sh
+dnl so there is no need for it here.
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "X${3}" \
+ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "X${3}" \
+ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[[^=]]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "$[@]"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$[1]+=\$[2]"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$[1]=\$$[1]\$[2]"
+}
+
+_LT_EOF
+ ;;
+ esac
+])
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
new file mode 100644
index 0000000..34151a3
--- /dev/null
+++ b/m4/ltoptions.m4
@@ -0,0 +1,368 @@
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [0], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [pic_mode="$withval"],
+ [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
new file mode 100644
index 0000000..9000a05
--- /dev/null
+++ b/m4/ltsugar.m4
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
new file mode 100644
index 0000000..f3c5309
--- /dev/null
+++ b/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# Generated from ltversion.in.
+
+# serial 3017 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.2.6b])
+m4_define([LT_PACKAGE_REVISION], [1.3017])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.2.6b'
+macro_revision='1.3017'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
new file mode 100644
index 0000000..637bb20
--- /dev/null
+++ b/m4/lt~obsolete.m4
@@ -0,0 +1,92 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 4 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
diff --git a/missing b/missing
new file mode 100755
index 0000000..28055d2
--- /dev/null
+++ b/missing
@@ -0,0 +1,376 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ autom4te touch the output file, or create a stub one
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# normalize program name to check for.
+program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program). This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+ lex*|yacc*)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar*)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case $f in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te*)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison*|yacc*)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f y.tab.h; then
+ echo >y.tab.h
+ fi
+ if test ! -f y.tab.c; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex*|flex*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f lex.yy.c; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit $?
+ fi
+ ;;
+
+ makeinfo*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '
+ /^@setfilename/{
+ s/.* \([^ ]*\) *$/\1/
+ p
+ q
+ }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ # If the file does not exist, the user really needs makeinfo;
+ # let's fail without touching anything.
+ test -f $file || exit 1
+ touch $file
+ ;;
+
+ tar*)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case $firstarg in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case $firstarg in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/resource.sh b/resource.sh
new file mode 100755
index 0000000..c73d681
--- /dev/null
+++ b/resource.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# This script generates resource files.
+# Usage: ./resource.sh <file>
+# Resource file is printed to stdout.
+# Usable variables (<file> is stripped from path and extension):
+# const char *<file>_rc; // File content in binary format
+# const unsigned <file_rc_size; // File size
+# Examples:
+# (file: dumps/test.out content: "ahoj")
+# ./resource.sh dumps/test.out
+# static const unsigned test_rc_size = 4;
+# static const char test_rc[] = { 'a', 'h', 'o', 'j', '\0' };
+
+hd="hexdump -v -e"
+fmt="\"0\" \"x\" 1/1 \"%02X\" \", \""
+
+# Preparse source file name
+header="${1%.*}_rc"
+header=`basename ${header}`
+
+# Get file size and dump content
+size=`wc -c ${1} | awk '{print $1}' 2>/dev/null`
+dump=`${hd} "${fmt}" ${1} 2>/dev/null`
+
+# Format file size variable
+echo "static const unsigned ${header}_size = ${size};"
+
+# Format file content dump
+echo "static const char ${header}[] = { "
+echo "${dump}0x00 };"
diff --git a/samples/Makefile.am b/samples/Makefile.am
new file mode 100644
index 0000000..5ac505b
--- /dev/null
+++ b/samples/Makefile.am
@@ -0,0 +1,24 @@
+edit = sed \
+ -e 's|@version[@]|$(PACKAGE_VERSION)|g' \
+ -e 's|@package[@]|$(PACKAGE_NAME)|g' \
+ -e 's|@localstatedir[@]|$(localstatedir)|g' \
+ -e 's|@prefix[@]|$(prefix)|g' \
+ -e 's|@sysconfdir[@]|$(sysconfdir)|g'
+
+knot.sample.conf: Makefile
+ rm -f $@ $@.tmp
+ srcdir=''; \
+ test -f ./$@.in || srcdir=$(srcdir)/; \
+ $(edit) $${srcdir}$@.in >$@.tmp
+ mv $@.tmp $@
+
+knot.sample.conf: knot.sample.conf.in
+
+install-data-local: knot.sample.conf
+ [ -d $(sysconfdir) ] || \
+ $(INSTALL) -d $(sysconfdir)
+ [ -f $(sysconfdir)/knot.sample.conf ] || \
+ $(INSTALL_DATA) knot.sample.conf example.com.zone $(sysconfdir)
+
+clean-local:
+ rm -f knot.sample.conf
diff --git a/samples/Makefile.in b/samples/Makefile.in
new file mode 100644
index 0000000..a992c4c
--- /dev/null
+++ b/samples/Makefile.in
@@ -0,0 +1,385 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = samples
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compiler_flags.m4 \
+ $(top_srcdir)/m4/ax_ext.m4 \
+ $(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/src/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIMD_FLAGS = @SIMD_FLAGS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+edit = sed \
+ -e 's|@version[@]|$(PACKAGE_VERSION)|g' \
+ -e 's|@package[@]|$(PACKAGE_NAME)|g' \
+ -e 's|@localstatedir[@]|$(localstatedir)|g' \
+ -e 's|@prefix[@]|$(prefix)|g' \
+ -e 's|@sysconfdir[@]|$(sysconfdir)|g'
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu samples/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu samples/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ clean-local distclean distclean-generic distclean-libtool \
+ distdir dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-data-local \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am uninstall uninstall-am
+
+
+knot.sample.conf: Makefile
+ rm -f $@ $@.tmp
+ srcdir=''; \
+ test -f ./$@.in || srcdir=$(srcdir)/; \
+ $(edit) $${srcdir}$@.in >$@.tmp
+ mv $@.tmp $@
+
+knot.sample.conf: knot.sample.conf.in
+
+install-data-local: knot.sample.conf
+ [ -d $(sysconfdir) ] || \
+ $(INSTALL) -d $(sysconfdir)
+ [ -f $(sysconfdir)/knot.sample.conf ] || \
+ $(INSTALL_DATA) knot.sample.conf example.com.zone $(sysconfdir)
+
+clean-local:
+ rm -f knot.sample.conf
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/samples/bogus25.com.zone b/samples/bogus25.com.zone
new file mode 100644
index 0000000..5260270
--- /dev/null
+++ b/samples/bogus25.com.zone
@@ -0,0 +1,16 @@
+$TTL 3600
+bogus25.com. IN SOA ns1.bogus25.com. support.bogus25.com. (
+ 20010923; Serial
+ 10800 ; Refresh after 3hrs
+ 3600 ; Retry after 1 hr
+ 604800 ; Expire in 1 week
+ 86400 ) ; Minimum ttl 1 day
+
+@ IN NS ns1.bogus25.com.
+@ IN NS ns2.bogus25.com.
+@ IN MX 10 mail
+bogus25.com. IN A 72.96.52.127
+www IN CNAME bogus25.com.
+ftp IN CNAME bogus25.com.
+mail IN A 72.96.52.127
+
diff --git a/samples/example.com.zone b/samples/example.com.zone
new file mode 100644
index 0000000..a1e3aef
--- /dev/null
+++ b/samples/example.com.zone
@@ -0,0 +1,69 @@
+$TTL 1h ; The default expiration time of a resource record without its own TTL value
+$ORIGIN example.com.
+@ IN SOA ns.example.com. username.example.com. (
+ 2007120713 ; serial number of this zone file
+ 10 ; slave refresh (1 day)
+ 30 ; slave retry time in case of a problem (1 day)
+ 4w ; slave expiration time (4 weeks)
+ 1h ; minimum caching time in case of failed lookups (1 hour)
+ )
+ NS ns ; ns.example.com is the nameserver for example.com
+ NS ns.somewhere.com. ; ns.somewhere.com is a backup nameserver for example.com
+ MX 10 mail.example.com. ; mail.example.com is the mailserver for example.com
+ MX 20 mail2.example.com. ; Similar to above line, but using "@" to say "use $ORIGIN"
+ MX 50 mail3 ; Similar to above line, but using a host within this domain
+ A 10.0.0.1 ; ip address for "example.com"
+ns A 10.0.0.2 ; ip address for "ns.example.com". Since there is no "." after ns, $ORIGIN is attached
+www CNAME ns ; "www.example.com" is an alias for "ns.example.com"
+wwwtest CNAME www ; "wwwtest.example.com" is another alias for "www.example.com"
+mail A 10.0.0.3 ; ip address for "mail.example.com", any MX record host must be
+ns.sub A 10.1.0.1 ; glue
+
+;ns.sub TYPE23444 \# abcedfg
+
+a A 10.0.0.4
+*.a A 10.0.0.5
+
+c CNAME c.a.example.com.
+@ NS ns2
+ns2 A 10.0.0.6
+@ NS c.a.example.com.
+
+sub2 NS ns.sub2.example.com.
+*.sub2 A 10.2.0.1
+
+_foobar._tcp SRV 0 1 9 old-slow-box.example.com.
+ SRV 0 3 9 new-fast-box.example.com.
+; if neither old-slow-box or new-fast-box is up, switch to
+; using the sysdmin's box and the server
+ SRV 1 0 9 sysadmins-box.example.com.
+ SRV 1 0 9 server.example.com.
+server A 172.30.79.10
+old-slow-box A 172.30.79.11
+sysadmins-box A 172.30.79.12
+new-fast-box A 172.30.79.13
+; NO other services are supported
+*._tcp SRV 0 0 0 .
+*._udp SRV 0 0 0 .
+
+sub3 NS ns.sub2.example.com.
+sub4 NS ns.example.com.
+
+d CNAME non-existing.example.com.
+e DNAME bogus25.com.
+f CNAME e.example.com.
+g CNAME www.bogus25.com.
+
+f.g A 10.0.0.20
+h.i.j.k A 10.0.0.21
+*.j.k A 10.0.0.22
+
+sub5 CNAME sub3
+*.l CNAME c.example.com.
+;*.m NS ns.sub2.example.com.
+*.n DNAME bogus25.com.
+o CNAME a.e.example.com.
+p CNAME a.sub.example.com.
+r CNAME a.l.example.com.
+*.s CNAME s
+s A 10.1.1.1
diff --git a/samples/example.com.zone.nsec3 b/samples/example.com.zone.nsec3
new file mode 100644
index 0000000..f5bf984
--- /dev/null
+++ b/samples/example.com.zone.nsec3
@@ -0,0 +1,635 @@
+; File written on Tue Mar 1 10:45:24 2011
+; dnssec_signzone version 9.7.1-P2
+example.com. 3600 IN SOA ns.example.com. username.example.com. (
+ 2007120712 ; serial
+ 86400 ; refresh (1 day)
+ 86400 ; retry (1 day)
+ 2419200 ; expire (4 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ 3600 RRSIG SOA 8 2 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ 6G4Hpl8WFCTVZN292HX+NaS1K8+oLaXK+2gr
+ tIp53Y1MI/A8qAD2HZ+bECnbedU+mP5PIJ8I
+ 4Q6STbZE3HpiaTMP8D87sJwgD6tUexHhBNgf
+ CPZQBdF2Gw/hP+yqeY89ZcoeJVimy6h56X+V
+ 7KM+JqRQ6KlGo8vLJTn/lo3pOq8= )
+ 3600 NS c.a.example.com.
+ 3600 NS ns.example.com.
+ 3600 NS ns.somewhere.com.
+ 3600 NS ns2.example.com.
+ 3600 RRSIG NS 8 2 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ 3VqU2AvI720W9frpY+jz5U6a25115tUmkC57
+ tr/fvZS2CEAYhWVEpSSFWKRApb70JmQeYgvt
+ pvdmOriyChzq4y6phVJxChYrFeTqVYS0AvE1
+ ldZ1k5xL6I0hIL6UXgMoz6nRZQ6T1qh/7G2o
+ Ge9Taqu0KroITTLGfn4HlyMViq4= )
+ 3600 A 10.0.0.1
+ 3600 RRSIG A 8 2 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ 5tOtdUUMjX0T7QWL/YgYga+HuJOLOh8O3to8
+ 3fWUvS5hmrR5/hWV1TRXSHCS0HKIaPBJCn24
+ DCHM91uTPNASrpdyWlIAXTJBDqm62C0tXOKD
+ zn/50P0cgqHJXa7f69FQc5V+oA/OGcOb2xpV
+ e/ig/L8xLcRTGFoYScNMObq9tlg= )
+ 3600 MX 10 mail.example.com.
+ 3600 MX 20 mail2.example.com.
+ 3600 MX 50 mail3.example.com.
+ 3600 RRSIG MX 8 2 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ yX8xQLpUeZCX3Q4Aq0PTsjEO+5HUrXTWSH1k
+ LQ6qozQqWW/SAvnYGkjL/MILnqtTFl07DyrY
+ 1y++Ifh2vW5wR11lrIUiftpa0QmSUIj4eJlJ
+ fc78wZa3D1g6ni1VDsRClEk3Gx3sfmf2ryjN
+ QVa3s++ZszKolUR4WjGGJuwmbFI= )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdtkxsfkpMv9P3oa4FGDr+zbs5T28hC2
+ G7zRsgHHSP1r3AS9JW8I3yCXI/DWJu5M0Iv3
+ UuOc5Q/lNoxmiMKipIP0UZZ97sRyVIK4RWfB
+ quVV0GKQ08exwUvUwkej9Uu5Ub0YcWkQXAg5
+ xVNpWZ5WxlVhcDVwXG/geikMJPyk6j2N
+ ) ; key id = 25581
+ 3600 DNSKEY 256 3 8 (
+ AwEAAesA9XFmAudDuFARUUn4fcYdwbPfSRYU
+ DVC792SMtnEl6dZBLujInZbbQiqW+OyVlo6v
+ kyjyQBDuS6aebN4sxO7UYz4vHxxJVuP/+H0n
+ /+UAyz11XYT8Rbsmpgzu3PMq5mB13jCjzZ9y
+ 3JBJjp5Lrk/jRjFcZapDpX/yXu0UsuuV
+ ) ; key id = 28635
+ 3600 DNSKEY 257 3 8 (
+ AwEAAddbawR+0U7Bz/2lbX1iwMGmAoYOHmb8
+ sQF5Jp8gI1tEtpsDD42fW4EM1i1tx7Cyca/9
+ u9MSFB14BapX+dxMMj1xJJg0RNTiswjw4DC+
+ 7idLwmQHDUMhZLJBqdGkSDcgfsXm9xNEdRrs
+ u10wxWpmqMUFxyGStSdGneqdchSRDgr6fihu
+ NExHeXp884kXUPuAXSYu02xtYOLLAAhqLeEL
+ tQAoyi901FwmmYhyu4eYK2aWqy+ld7JCZZbQ
+ j4/9zdecIGETI+NbvQVoO5lSGt6GY7cKaf8m
+ 17L++dj2R2rTER/R3gwnjAGQ1GL/djhqbgMi
+ vhrxqAQ9R9Ko+6kaeqA6a60=
+ ) ; key id = 6190
+ 3600 RRSIG DNSKEY 8 2 3600 20110331084524 (
+ 20110301084524 6190 example.com.
+ qRB0bNPGgy4p2kGBNKbjK/03dowH3zx4fLyP
+ 6wv4VmJinbqe2hxqLNLGTdA1toT/82iaLJEA
+ Nh0GKnYRVW1rmX/YsvArYH5Z8ikrZbTYSu7Z
+ TVTJHHXOGIbddpx3BaEPeNJyJHf7UF5yDKkv
+ wM8KhkMw7zRWnuLw5dWYTqmegMVHkNekIHrH
+ kW389rY7gbNsZexusmsKURhl3/LhRJlZd/hP
+ IlAUIhEV0DZ2xmFEkCOa7QRD/PMUwuiEykxd
+ 0ffGm1aCzBUUWdVP7tbYbsePa9f380473m6U
+ xDSgNmU5/NjFRYw79/QopE68OU+7F+xTX+6S
+ U6bBtAvTPoG+RIBUAQ== )
+ 3600 RRSIG DNSKEY 8 2 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ MD75IQDQQtrDQTUHJV/F2cYfd49e6YkSWT7O
+ BuJUnTvyuYyxpqJg7Rj1H552078yrUQiNSCC
+ fqo9yoW6QrpxXgAsPW8wd4vT/bXRayvqZTRJ
+ 6ht4FMvOe1dI0cMEOEGfOnve1r4faaHBYPIo
+ P5sJQIkoYpQ/0FOnOLz1dIiFZpI= )
+ 0 NSEC3PARAM 1 0 100 8B3F579FA62A6CE6
+ 0 RRSIG NSEC3PARAM 8 2 0 20110331084524 (
+ 20110301084524 28635 example.com.
+ Go3s7HQ1n+WLlECouJi/2P0h0F7buRYP7zSE
+ UcjBgBDczSucB8ZdfSI+Z9gZpJrOL+hpnhU5
+ UB0xVUldoWzO3KK/Zu0YEoBNf/z1eSA8Lrt0
+ kWtxDlppfYk9rMRJIBEkY4nNKJz/IlPppZ8j
+ TY361bbHGhoHmjJeozrdMGc6/Ls= )
+_foobar._tcp.example.com. 3600 IN SRV 0 1 9 old-slow-box.example.com.
+ 3600 IN SRV 0 3 9 new-fast-box.example.com.
+ 3600 IN SRV 1 0 9 server.example.com.
+ 3600 IN SRV 1 0 9 sysadmins-box.example.com.
+ 3600 RRSIG SRV 8 4 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ 45kpyR6Avac84Ycv/EpLT3ScICeNpLFgQq7P
+ peNgEpboXrJTc7uYUtoxswq19m9czMNQNcoZ
+ nFKw3unQGrsfr/B38Vz6uOc9ILF/4WQbC002
+ F+VGlgGvPVc9RficEYg3Wwzly7m27d4hPwk4
+ pnQQaVenubmXgVHKQ+kl1c8Bqu4= )
+*._udp.example.com. 3600 IN SRV 0 0 0 .
+ 3600 RRSIG SRV 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ zxu5UR7j0cgvdw8q1L8eD2AvsvhkhbSvuFQH
+ C8a0pYCmM0OoDEiLoHj5F9Mk7LI4Mc7sESfr
+ roKEOQC4y6xwsuQxCjuG+V2s4xnxLbSrZwee
+ JqaI3e8X/gVfd3VoKycY3MqDC1432Qc8VSZC
+ Lz9mb68ulNEK1VrEbbA3/jTGGOM= )
+a.example.com. 3600 IN A 10.0.0.4
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ x30rkJBwLV+aiDao0J1N/FbiUWROwBqkl6lK
+ V3z4zHfkcEgORa7o2kNkHANPCUJj7bQSSlPD
+ I99dyszDxYW4bgnlNlYw9h3D+6+sK9ehREDa
+ IMvV1Xuup+oo6LccJhZTlEFrGFU4oUF9VXj+
+ g4TDzCyCGMHnVj3SFc/+5xUXGsg= )
+c.example.com. 3600 IN CNAME c.a.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ 1sHLDUiGyabatbzRknYdhwu4CQXH+bb6+9x0
+ yW/173FMudGOGowiPdfMkUFOP0Igqb/4FqVj
+ bg+jDdu4zFCszLQ5MC4Q6mrLL0nfUJ4JL2J9
+ kScZN12/t9+P0dnLb5YYXKV8E0GtlKd4ZVr5
+ 9fRJvve/OsV29Xj02vX1+sXNjoE= )
+d.example.com. 3600 IN CNAME non-existing.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ Or6i4+ez4nkhodwJC8OWJaj9TyvxJ1i6HC3u
+ /xjwF/kStCkTaX/Cg8d36KhVGev6z6LyT++s
+ SKiQ0wdPzhgfv2d386W7XUSCje7/OCRUUZwp
+ taQvzJsfKCBy2hYz00Anai2qk1pldKEYI3aN
+ P3qnSItISO9zbOcKtV2ug6B304Y= )
+e.example.com. 3600 IN DNAME bogus25.com.
+ 3600 RRSIG DNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ sbrGVq24p55ke3GGXkr/7IPu3fNO67SUABQW
+ 67VKrfL1AF5qWN7UdcEb5FZQ5302s28/mePb
+ c4Ubn2bpQrmHdMZm1W370J0fDQ/PBT9lKnQS
+ tZpAx6xPMRmLG+qvrOtGFDeuCVDqmRlK13wJ
+ ryCGvI2eJcfrOU7Kx98ZLgDTzbQ= )
+*._tcp.example.com. 3600 IN SRV 0 0 0 .
+ 3600 RRSIG SRV 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ k9YqgNDYkvF4tqiPjw0FCsL675BQ6V0mztXc
+ +Vfcd/bSbpD3HiMDbkmBeW68TH7g2rkqTzS2
+ yjXGdVsxo7jDWdfPiGDdAUueYbPzxEF1eY3q
+ v7oquG86sfTrbosYFPfihLXZrnGhVDIlHmgi
+ L428BtZbXTINKm9XwjFwv+pZ66s= )
+g.example.com. 3600 IN CNAME www.bogus25.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ gwENYoTmnyn38R4sIb1wJ/uKXPNQnKOu2gfa
+ sWW91lrkcwQYF59XZIDme+XST4fiscDJfjPH
+ 9xHXs86j771L/2shVZkfh161qXMv2xWVKP14
+ tXXfjcQyz/YZ4S6S6MWkUl1w5ujqJCq4PLv0
+ +BucVmtjQkcxG9yR0P8F5hMZBsA= )
+*.j.k.example.com. 3600 IN A 10.0.0.22
+ 3600 RRSIG A 8 4 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ MI/Q/zFqnUrlIQmPjy4Kpq8lQ38PAi15cidP
+ C1ZutJUXV7aiYpJJcpmkDNRA96L+/cApfW06
+ /ahv+IYrxI3qWd8agOxDXTR/bclrxWJs8Zdq
+ aQeM+uvhtVCua6tRcdJf1UCHwEFpqoEg6xcs
+ 3vR13IuPLlJrfe/AMrw1FvROfBg= )
+f.example.com. 3600 IN CNAME e.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ cvQbg2jKGDrL6dyOXSY++SaEzo31OKDPRXWe
+ l4pVWsJdK9YmjQ0zXdAVtqiYFdKsfS4ep5FG
+ VPFF3xuHF0cPzzozwQ3cyn6BRq6EVDohn5Ct
+ oyqSQ9jWuwDNdLxG6yCFK+R6bdlc5fxE3Jkn
+ qQ8hK6z7XHpHL7ZySVufRtGhMrA= )
+h.i.j.k.example.com. 3600 IN A 10.0.0.21
+ 3600 RRSIG A 8 6 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ m+FuNt4WmfnICukl82DSunja8nfoy68u+oBU
+ MX3nzp5AjwbqWyZTvQRaZpDa0Rsa90oHbCuv
+ hOYiK4tVdZjk0yd0Fx6XX/zFqD29BEI/oLu4
+ u8CPLvSC9vWB8bFScOjeoCUM+hmnoLVuZ/rq
+ XFHz/CQmYX+mpU3u7pKSpFyQDAw= )
+mail.example.com. 3600 IN A 10.0.0.3
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ HPK9q98C16xCURI5wxP3lxUGdJr1X1TeRZ2L
+ tnf2s5Izmt28Y3SIbVI83prKO/m4PrpfeV7T
+ Ji3ErMMUe7k6Q096YaGStBHL5GWeymJCAzC8
+ pJPnyzExDRZeGeknEg4bn0+WJHJz+hlVzYQx
+ LRaqA4O021aZf9U/sdDZhGBR0Hw= )
+*.a.example.com. 3600 IN A 10.0.0.5
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ fXOfzPtCYPPyxtw5ivLn7Kq3JlK+LR8BbYLp
+ Z6f/Nir3R00GURfsUM6NVbPnMOpnPE513yz7
+ 1sAAO/rsOFXPZUSJF4G4zMA6O4OirjGh68bX
+ Ei/yrdllyPiTgtHI693MpsDvAFNIaO+pkgS6
+ zt+Mk1MEau+78saWxyZVbBWCqT4= )
+*.n.example.com. 3600 IN DNAME bogus25.com.
+ 3600 RRSIG DNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ s/gyETQ20pNXEbhwRhTIPTMOQYMW8KhhHaSN
+ uOYX57dabeGuYgfXFRfNIB+Y1m3kTlxmacMS
+ dNIep2b4SF59/T7Ww06/I4P/qQiOosdyeBSY
+ X4mQeMrUh8kqxh9C4cQh5yPiiz4w/0Ui+SLP
+ J/7Z0AKgYKh7t+pVQfiDAKGQJXo= )
+ns.example.com. 3600 IN A 10.0.0.2
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ aPAigU/glISbY2VM8F8JpfElQ+xab12ZO7el
+ 5Cl3t1qiU/3iirBmaKTj7g6IhBduPx+iBgOy
+ 5v32FyrfHi2El6nJZxEgi52/Z/4Ohvju3jVA
+ hUJLGoREc20FUXOiICCftEauQp7uPM1RAQ17
+ Q0pykRRQ50bn+jApSRLL696e+EY= )
+f.g.example.com. 3600 IN A 10.0.0.20
+ 3600 RRSIG A 8 4 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ EfjVvHQ/IEPdP10B+dEDfyHpCRNpmf0dV7Pb
+ Ia/gRDuoRg6FUbL04oycNQSMjafInBpinmx/
+ WSDMenEf5HUtP3fyzZ9Fywg2QDZqm6/TJXBk
+ 8q+uOxPKfMlcn9Skg1k8XJGbJkAovmyCS+DA
+ LC2Ewp7yVUwEliZBkKzUblWE5ig= )
+ns2.example.com. 3600 IN A 10.0.0.6
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ hgX7gI1GpJeuQtTnVDCHS4esc1wRQk6zAP/8
+ st6cILlYbOQkwfRVpB88Y4LDCYuWLkplKBjp
+ cOhL/gU+zvR8QQQHmdksUlYSK0SFEdvcpvIm
+ uD4KosW3wJSAPS8M3bxI2yA/CPdY6SalClbY
+ jM/OpPfynAqS1UdNo8vNu4pBYks= )
+o.example.com. 3600 IN CNAME a.e.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ RMRnQd17zWB6vxGUl6L+zKWchPD9XyNMaK6W
+ v0MfpY5E9hqSMvNp5BKf+1Fsk5aWs9aWga/a
+ AVFUTObelpdG4IE4oyGSUB3wCN9ZTxJ9rKqd
+ NVG48X2+iAb2k3tGcUQaYH20gBIezPwi2AWc
+ k+CHI2FTi10evykIeVJo+Paro7I= )
+old-slow-box.example.com. 3600 IN A 172.30.79.11
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ LfF5v3pRRomTjLMLqCyEqK9J9m7dbBs1V0zS
+ bEu9T+MPOdW4swoObFBPv/FLqr50Y6OGlovK
+ J0lSGo+plLw6gPMW9bzJNGeIP19TgcEmF626
+ 7+hRibwn6fZvoK4qBQSDQKmNBoST1u+ZhWa6
+ xpdY5bdosyQ0oM1Q6eHZsEGELvs= )
+*.l.example.com. 3600 IN CNAME c.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ l+p7hZxP1VakVXtcDE2dN+DCK9tAdZpT8i0i
+ IoUdRUgeTv2DcViVsK2tNjv0HIZcffhEatwi
+ pM7IAvqkbS22PduU+dxb3OMzcj6n/dQBcxoW
+ vfk56RpQcDrqPJVYn7AqVH6KXFg6oRrIYzw1
+ O9uTLaHt+futcIEDvRVMTODe9os= )
+sub.example.com. 3600 IN NS ns.sub.example.com.
+ns.sub.example.com. 3600 IN A 10.1.0.1
+sub2.example.com. 3600 IN NS ns.sub2.example.com.
+*.sub2.example.com. 3600 IN A 10.2.0.1
+sub3.example.com. 3600 IN NS ns.sub2.example.com.
+sub4.example.com. 3600 IN NS ns.example.com.
+server.example.com. 3600 IN A 172.30.79.10
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ zWLeUhLq/2lU0KwPFxzJaFIiOSqwA4xQ+mwh
+ UYSa27N1t58m3L+XeOwj/zSE69sWl8Lbm3pV
+ B+4FNVVPkGzBhocJRf/7a0xc0IlQSI1hgZ3p
+ meFlPC/kMTmxK1p9un/dF5r35FsnnAN8ECnR
+ 2imbaQLIrjhHshK9bBIVCwK92Ws= )
+sysadmins-box.example.com. 3600 IN A 172.30.79.12
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ WUp7V4gH7JMyvtKURuvrNmW7rVMI1aSMZU9U
+ xukVAmQDaQTYXsD5XC3j7X+9gAhQJWA/JNga
+ pXT7wzBJpqVrJHqAfRYZFMQ9WI0rJzKJnFPI
+ WOlVerQMEwUpyJsX/GlJglldK5kKM0bbPjW8
+ s6Vqmq3rfyjGY94HNS9jX+uqCwk= )
+new-fast-box.example.com. 3600 IN A 172.30.79.13
+ 3600 RRSIG A 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ qK9x7sS736Go3vdVfYhtuEnFLOhl6djWpXVC
+ l4+kvvPpkAJTkfHmTcAsWbChSolB8X4UPt/P
+ KTnImnF4uhc2qLOhvToKqx9tVExEIWDBKA7F
+ JPPBYG0c6n/50j2bVmzrkhyzaLLuhsbbfm5o
+ eZDwwO+vuoMBvj8Z/mt0Di9rh/w= )
+www.example.com. 3600 IN CNAME ns.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ LPrX8sh5xYUfW+wKpQRg50qkf67maJRcN6tH
+ R+H3OwL4u9JhdK6RpdRvs4nAF8HmrUZZYtxo
+ 80+RMbFhynqPYWlnXd/ZH6taQN2qJYdVLdnd
+ dhyLajAkxJqpOWVLezr2KOPj6YzJzu15ngXD
+ nHnkSKsTlziq3ifLd5oJLy9UJAk= )
+0J3ID6U2GQUPOADI9B867SGMROP8U4Q0.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 18DGVBOD0NE6AJ2OV3MV9QGNBTJ39V2U SRV RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ BStj/PbAk78rRKdCf4eCvtGKYGco/i7fg54U
+ mlIGY/ToQwsB4f9NuDpuajdt+30QnL6w1m5u
+ /Hku6cZAV7PEr5S286TWtIHu1GSUfjQ2ObKC
+ sF9PYoQrARTNYceY8ZKPNwTk1DgfBNM1WcdW
+ 5zJLbQ/DfP/O1c9ZiaR5jokbRnE= )
+18DGVBOD0NE6AJ2OV3MV9QGNBTJ39V2U.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 28CVPDQCRQARAVE71745J8C1C9RR9U6A NS
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ LeQC7vW1322QqG/X08ZQ3hokSMIDB0rmGxk/
+ JsmrNt6o1hmpwfz9ET1GM6LDf+SLd12SdnYa
+ vRZxVVeUv7KloxZI77aaZabqKYWCX+LmkoJk
+ LAinY3wQ6vZD3vSP/BxUZL4Ojs0GNpWqGNzs
+ ZOkU9EOOE/mwQFlU6GamBJoy2nU= )
+sub5.example.com. 3600 IN CNAME sub3.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ qIPaS9aKJASzy2ncqcnlyLW4npkwBW12Udvc
+ zGyjk/bO8Q58eKm3uBfJ3LtQVCznkBhAksXK
+ AXGnN1TRtaxeVBWZNqlRtHV2hgmXQsTWxoVz
+ Qc8Qz2LvnzfgRTjt0H1n/5aDQ3FeZ25XuwLB
+ W5fFHwvOmQDd3lvZhOJVfSvEKNM= )
+28CVPDQCRQARAVE71745J8C1C9RR9U6A.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 2BMOOQEUMB3KGE328CJ7B2Q65OPJM8DJ CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ i2K6FAon2wyZnGTH35mMmjWth+czEC1cdoyL
+ hk6Xd3iGrN5tjPAqkMtuKDuG2boGjDP02npj
+ Ytv59m5IK5vSNgeOekR6TRNWdJ/S3XM9VSlv
+ 9R07P9WjJVjO4viGtAfvbKVNOYyLPe6+e/Na
+ lIjYv87EAAlV3Hot7Pzff1duRSM= )
+2BMOOQEUMB3KGE328CJ7B2Q65OPJM8DJ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 2CIJJH4RBMAISUSA1TH02A2RAN03THDQ CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ HWSQYMuhCxYWm6DVKRwnik/PYwQmdZhOHMmb
+ P+Map173RzL0kzCqGzpokaDmZBs8zZohgvMs
+ UYbQss8jnXJuAcyRF0dSc0IVVeJLUAaipJpi
+ kmzyIy/+ANxsaSeRgKvkGecFT8dnl5xNQ6F3
+ vbBwGNQ34VQHNx6S4a3Qa/vBwS8= )
+wwwtest.example.com. 3600 IN CNAME www.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ 2kfR8e8X0LNbTyPg9fe7vlOknc63ksjBRECm
+ pCKNFqSMXJ9gd4gbB2DKHTQLarAQx1KOy3lA
+ OezcuJS3WKxF/ucZDqkOaiN/YGJqC5GZ1jcW
+ zcCahY8FAM/eJfjbZpdn8YowVQy9f/1m+agl
+ vsHMD00nflPUyFiRmoik1DAWoVU= )
+2CIJJH4RBMAISUSA1TH02A2RAN03THDQ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 2E74KFMC0MPQFVMLM1UD7O7HCEUV01TQ A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ f6Gj3qbdYjC27HqDBLv3Ip5Gf/j/GJNVko3G
+ XIVrebHqTPUssOy81/CRElLstM1l1WzX/KTz
+ 9Pzu5e1qmlYk4Ym20mMAyihWON3/IJk2GI8x
+ TDR4tJ3DBWk37l1S4eMhjv43OSms98GlKfZl
+ soYKgv6hwPyX7si1FEL9gWTJjio= )
+2FIB35726VOBGISOGPQLFO6O5IRN3M0G.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 3JL9UEM86R2IO5RMPACMSD92NTVGRPNG SRV RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ xmeQ5RA8LUt1UDtfFhKdTCq6ean35+UdK0fP
+ OIb7XeWcp63YVS28l0uoud3+HjsB8VSF/FXi
+ PpJnN/kG6Xk/+sdTDGuObtqlAI1W6/dXgDcP
+ VdbGNo4uPcJsdkQdCgrQs0oxZCwpW2Q69LWH
+ yKLTVO6avq/V9DiNOPjTSG7Ix8c= )
+3JL9UEM86R2IO5RMPACMSD92NTVGRPNG.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 4F4ISAF7SLHE2FVS6IH2N1HHOCVUTMTN A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ JbwLpP6KcZ4UbuR7vmjRozuL2uoyp6U1HP9L
+ tRu6CH5CJwMa0crXBM6cCg7zm4PkSxyQBMSV
+ lt+T3lThVSx6HzxGoDAblj5SiPF/SA79zZW6
+ g9qFAlLQ4doeC0CesjeOPu9bL37wtWJIZY5P
+ 3LhYhNN67PYAwGFl+s+3kVrLiTE= )
+p.example.com. 3600 IN CNAME a.sub.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ eXmvtean3kAh6cJGtMWPfzVlOC6cjaF4IgIC
+ UnJruUTcL61mR57nQKxBD6Fc6/BQoVMOvP2n
+ Q19akZQoDvgt/p/Koo3vUozrCzLvkj1n4oSd
+ R0fSl7PCBl8Rf1TMuvw+7XvQeIfLq2c8INL1
+ PONXmm/lkgqbYw2BJxzx5tKffcE= )
+6A3ESFQICSC9TLOHO0P20QB3T0H8DHNT.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 6T8FEOHJ6MH3O1N4B0H6AES9842FDUSS A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ kUhsVZbbmfkCczTv/wMzX8sbPn+5VbR1r+xE
+ x8YvzZ42zof62wIvS2JcwXCR2GvSi9LVKBQE
+ 3y1g548Y8n9moXC13MP4F84h+5U/VAhyaPpw
+ e2TJpBnMLCDjvMUXP3XQKQzkdiV3UaLFn0aP
+ khwT6nh+TTPYeREjcSLuyhWs8Hk= )
+74EBGC37NAC14CAFDT47M48A5JSFFSL2.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 75DLOF6I4571LIKU0GLDE5T49QMEN8IG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ MtZCtVby4Hprx3spzSglrUqmPvvreRDrKXhc
+ 0xaWh27f81oGsnek+jDYvaw9JIdDcOAQbonT
+ 2nVy6s6Jmrjt+7pWSGPkuFGPgybBrH1l0Rh3
+ QmODDmVDueyTMSdEpfe+Nw7+zlq7BI1qXe3T
+ fBoESwb73RXgOQ4VztK0/XXk1wQ= )
+75DLOF6I4571LIKU0GLDE5T49QMEN8IG.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 7GD2384TAD22TQJ5ULAC03C93FO12QF0 A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ zukfY1bN+D7H/q3QKmPz+rRRxofgC1ECjbxL
+ ZdG0NBT/w2QL3wRLe5CDmy4hNsU0Iq3xxeel
+ 7B4f/CMkY+F7WXBbFwsi0cLf0gfN+VOMcFR9
+ 700/L99AUw8ofRkH7sWNj0sfHB/CHSC38980
+ u+n453MvcT31Svt6GwBVtt75ZOc= )
+7GD2384TAD22TQJ5ULAC03C93FO12QF0.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 7NS0GBBS9N6L1E3OM48637F6HOKCOLQB
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ 4nqxLigxKw86DpZ0KAo/k0507oWoind1FOCV
+ GDJvF+YejkSuvJFpAtfVSUrw690XZ7+zyuoV
+ 05e7BH07rcJV9TeSTgWe86nIGegDr+yzZBEZ
+ 3eGsbCwHxrR9ROieVBxNpWnfkVrA6MFqHZj1
+ trAY6ajLrb/+kQEBaBdPC668tJE= )
+6T8FEOHJ6MH3O1N4B0H6AES9842FDUSS.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 74EBGC37NAC14CAFDT47M48A5JSFFSL2 DNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ i0z9WCo2snvGjQJvl2ZOkzg0PwCBuCPlDZ2U
+ NTbw3k/P4N90yVYu7IuJVEOuwPNaKHzBnz1u
+ 2vzYxM/fJHkWi4FljRFGGHC2ViBKJS+li5FK
+ KVUXwqZCHWlEc5tZ6lrpFTv5Q7h0zC6M3gSt
+ kBl8r8CZY75Yls/xGk7NZDd40R0= )
+7NS0GBBS9N6L1E3OM48637F6HOKCOLQB.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 80I3RRJLHHEFK8HQHD2A8O6VBHGKBSJ7
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ VXcnf/ptpsoJgahBd0QYFkxBqyBE7ZOPNFJO
+ jT/fh6syVGIuV/FVSPY5c24RTs0pU59FPW1e
+ Ce1bDLWR30pyZfXBrwLmvjwn6XA+RhYtlBu2
+ vE31i9zr8pSnZ3GU553zE/30J3ggO+WLQy6f
+ sLMmPynGnACOMz8hwvAuqATLswA= )
+9LF5T2M8139TAUL9LBR53N1RLU9BLIFG.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 9T92PKASBK46QUITTDHH5T7U73HFLO9A
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ vJJLcMmUHJIKxBS1a33EljJpocAmudNOZJ1k
+ KKpoHIfhN2U4b2GbaAQRbPIttDW14dmwuqZg
+ pi//Vm5krSx1PrVWoaCwvyn/9Fey3PcY4zWX
+ Rj5m/zgMrqnK8mVdnCVTcSVwlgpcJrpiYxxA
+ 5/Lj2MsiY9vf2Gk9kcYqyg09iqg= )
+4F4ISAF7SLHE2FVS6IH2N1HHOCVUTMTN.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 6A3ESFQICSC9TLOHO0P20QB3T0H8DHNT CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ QO6x9M8tKx9nEwTGTLOmWJm2ReQWdDJq/s8x
+ CyLc8W1v38iqMgP/X0e+un2MicXkG9Xx6bn/
+ KBCMVx16q9MFfpdyQaxvc3w0ZvRliAupP9iH
+ pFS5igBe/BAnUS7O6jjAaY03frbz+JaAmNUU
+ qbyEm+nfWWDWmPpVgU9qMTh4Iz8= )
+9T92PKASBK46QUITTDHH5T7U73HFLO9A.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 B939IPLCHDGHKH64CLV0F799P2QFKODM DNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ b08XgQYnvasffMbun6yS0gohnuJL2TklNPf8
+ AA+2g036YcXQeLTHHMgzgxrpUTKVAnBP8G4U
+ gWD+xRwsys2q4Ws14oG9SAos+YEcus8AGs+7
+ AFtHyOyBmRwOgP90Iu4W27bpIYf8D0mTC/vL
+ JDFkAVYzcL5DW7Rx+pr2F8bqY3I= )
+C8BNH0HKUBJF5F9Q6TV3BLVDP2H05C7D.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 DB9UE21NARLOFV0U06U8CMVKP4GNC10K NS
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ bxfqIBTAIogKzXbyqPnlv+MFIyoYlIT6knm7
+ F6BZp9Q0VXNgVM6dEU0THhIzPvaMszn55Tg/
+ lEohKrDuFWgbEbWpA9CQEm3LFLVg9QYuYl4j
+ 3Glym7TdGl3PDGagEpmHvLHx4gKbnqZWtN6J
+ uudu2UAlp8EUP4BWwsCsbnzLk2g= )
+80I3RRJLHHEFK8HQHD2A8O6VBHGKBSJ7.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 9LF5T2M8139TAUL9LBR53N1RLU9BLIFG CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ A2sU+74sIE4X4Ai2pzJPngzssUG9q6FTrBA2
+ ZcvOZtkzS1hY9OafSHoyKonqlRC9A+tX8Ny0
+ by2M66eX4NvlinGyBJWdC5Ekj1b5cMy6Pcig
+ zcMAGsj91MZOqA8gwKiJ8xRGF/LUf1YdlQAb
+ qD2MLj83BSzg2m5lXl9EVMLmQwg= )
+DB9UE21NARLOFV0U06U8CMVKP4GNC10K.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 DE3D7U7081COUA3PSVT8MLFDGNGNMUTN A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ VPzYwah96Z+CrgO1cgRHzAe6DCDbn0wxGvfS
+ X7suIoXVhz71+PCksxmBzXCjEX8hkta8bfgy
+ KEweSDw/PAGeBq/gktmx4XravfhSrvcdxfyC
+ jaJQDfKvf//iJKujR4sP1crWnTNKXNLNO4io
+ AKiecOcs5L7FFLf/mG/tkRrZD4g= )
+2E74KFMC0MPQFVMLM1UD7O7HCEUV01TQ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 2FIB35726VOBGISOGPQLFO6O5IRN3M0G A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ k4LLw681oD7qIr/GUupQFuOlbUJe0XkH5YHB
+ hG19hIy4BXPGYI0UEaxLnPcLsvhLgb+sdWTG
+ JL1JrRcCMRne0zNMY28sAzO1npbtN9pd9oK5
+ ZYe5OK6wXpIvziGdJ/2eUVEmV+NrSJREgPbO
+ krsX8SxFss/S5i3C+UoWHQd9LoU= )
+EE6P9GRHC60PKN1E34GP2GFODTK9ABNL.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 ER30P5E30F7PBIBO9JHDUD2ATC20OKNQ NS
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ N1IBfELSSlFUJwA9WBo0CtNHwvsWrDnVTUGv
+ Cdfz3mp4H1CIUtKx36zX4CJeVXtwc+zWgKki
+ WZvpc00L+uvP6tIyMwGeshjd4etY5DqbnIuH
+ mCbIxGpVqgjhcAahCogG0kHBnNWkHYD37SZ7
+ 9J/uwMoNHUGqpEKiy9PeIHfX3zw= )
+GDU5SE9F3JUO6HF8AONHIVJI53NAE301.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 GJPHM3J2JR55KMCICU1NPT84KMP1C4UU CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ 1M5Lz9VF7zkSQWN+uUUHAvCIzj54/eRvqkkV
+ XLjviMkQ3G90qrS7Ro3FN35fbVdgn1sets/r
+ R87yO3TpgNwWjcBejT0KQXr3VI8me/Jr/yID
+ HlXpfkJZi7YfOs7Us7pKwlzXz6Ox90qtC0ce
+ 8WXbjdjrmdpiLAsdZxo1miQXTZA= )
+ER30P5E30F7PBIBO9JHDUD2ATC20OKNQ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 GDU5SE9F3JUO6HF8AONHIVJI53NAE301 NS
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ TKkytnNfTi8pvoqjXO6V7CY20Zr9oosNb1/z
+ 3X7s5UBDZh5KR1aSDjFxt1FrY6+SJkTGHfC/
+ 3pNerSIecbMJ5Y2crLJReXFt8zafrL6SLI/a
+ 2QwFVuqVWzacwN+0rSxCqcz1tUPcztv0KSv4
+ 87yK39umtsKCQ76PaucVtj6DNYk= )
+GJPHM3J2JR55KMCICU1NPT84KMP1C4UU.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 HOJ16G88JKIIDO9ML2CJFV5SNJ8BFVEI A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ QYhzXTmXhrSEsN6ue8c0NgSTaLXVyauv8cTW
+ WA/Wa9MDa3+OzaI/X5VnDZOumbnAbX4p1EC3
+ yHDrXC+QnQrgr6/Gj9rqCaNzyXKtmBYIGUvV
+ DZ4ZRayXeYc/18GgWrCx1gBTUsjsqy1ON/1K
+ i8R/aZhwzcUvWbqr1FlaTLSvk78= )
+HOJ16G88JKIIDO9ML2CJFV5SNJ8BFVEI.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 J2A0018O0QCSI08D608LDVJOLPTB3G96 CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ bnvyEDA/snJUVw5jBhdMZ0ajEE4kcfiXVSM/
+ P/cKiCEMgR+xhDrz4sUSWitQHz75QXLybgSj
+ cjU1XrjGP53kWGb3YEtWaM+JaqV/1yZEdCDH
+ ny+zyxcI0foYPu/4r9uqTWB9VLIRHCQol7kJ
+ XHu88kXYdu44hdiqQf5E0+VSdfQ= )
+J2A0018O0QCSI08D608LDVJOLPTB3G96.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 K3MJD76QQQ6H0RKERHB88S6LHEHOMJRV
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ jIknVULnzmGn8B3LoTKcuU6ELNYyRLagrI37
+ XrnvlLjxWcqNk8W5aiNcVMhfEjlu6F2zLGLU
+ 4K4KLV1efxNfJpcp5Ki0lNS+i3HB0rkg8dP2
+ j+UCsQ9wHbwzZNSbDli3/kQzEwnHvuuy9f5t
+ WCEXC1dwVt0QDrVu9yNVgXuW5SI= )
+N9INKG4137UMU0NL0U8V5FOTD66UJQIN.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 OBT94VQ2BVN9NBPVL65OCARNBQ92R9NS A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ P0xnjLy1AbyOUDyM1lbApfQxQILKU9m3lVIR
+ 6a419fA3jkFcBoB3A5ReXWFUW+lYuVGAL7cX
+ na/QB4J+skak7oEUz03Hoctc3eCR/ud7vobY
+ QULzq+cHzFsDUFC3b8ie0NWMZH8GNRGeHS0T
+ FtlHk4mQofYwQkF9Dbzdwn327iE= )
+OBT94VQ2BVN9NBPVL65OCARNBQ92R9NS.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 ONKAPQRU8HJED18U7QPRPJA8GGKP5RCQ CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ uhM8yr7khK1/Ii3buLO+oHUY38t23CcSApyP
+ RUefb87LREQVtcNh26Oymd741/NfhvZmhop7
+ Uvx0CxSICmjdV+u8Pm7/fbFK1Ha5m0/UvrUo
+ 0M4QNEGS8Jbs+xsshr8RbaBCpUStTCxz5og0
+ E4lFekJEXuqT7wa/0TVBRyzWIQc= )
+DE3D7U7081COUA3PSVT8MLFDGNGNMUTN.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 EE6P9GRHC60PKN1E34GP2GFODTK9ABNL CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ onPGqq1wHK4TnzDM0stR93s5SsCWFMQh0l0u
+ 3lVmvEh8T93G7OpfSEhRoQ9td9o5NxHSR6V0
+ 4xxgDxvnjgMMbvDvgyeHLtnmRaaJhC6xL6jy
+ 0UQYb0Dz5S5aGocR6tvgDu8vmDgEmTx7zMV7
+ 8vdwz2epzT40MX0hGAw9YhYdQGk= )
+B939IPLCHDGHKH64CLV0F799P2QFKODM.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 C8BNH0HKUBJF5F9Q6TV3BLVDP2H05C7D A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ nUn1EpD0cHWC8C9RnfBt4wBepa+DGQFU3nKU
+ 2+75RSeL1ltptxuuUmhmiBindtODFY10rdtP
+ TecPL4dsG5CXIZzx1zO0OMJalYFyN3MAnZXS
+ ENv/K7bWTal6OqVjxsYfrCqCcEmYW+8+0b+1
+ vUhfqqaIAdCgVGYrzXMDoQ80m0A= )
+ONKAPQRU8HJED18U7QPRPJA8GGKP5RCQ.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 PO4K5TL8FC932CHVR1339QMSVCG8TFE5 SRV RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ d+sbaGrwmTVOfTajPdsD9NHEUpLXjjJ94Rpp
+ 9HIvdJozkwPOP4nUt2lc3lZiJ1OhK/GbMkHZ
+ wFlkPKmGeBPoa6FARpYuFj1DtDZhWCd+mTH/
+ VMSzGiX8InCQGoTTiufT1G4aSP21oY+UtduF
+ KHJYikaPULyWgWjbqOpoO0OxFtM= )
+Q373J0K0LKK0NE6QLDMCDUMUS4D7N9DF.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 Q89JNCJ55KEMLN012BN386RRG5V35MGG CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ ESQkjbD7LTon4QDSN6tZwU4ZaPopzvIXfJ5d
+ 3UorybWbBVrctR0AR4mvjuaY8jPuxjcn3awh
+ B/RwtlQ2oWrquPfFdinx60v6hmbhFJRSzIM7
+ ob6tJObd6Be775r8M9N/aEi0ghtL7qv4BO0F
+ 3aoN1TKFHrFB58uyjmtNUBYtE2A= )
+Q89JNCJ55KEMLN012BN386RRG5V35MGG.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 S6102U94KPK3HL2EEB1KU341JC2EMML8
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ s9GsCDhpCzdFG/lnYS1EXxD1yqW1Rs8NFsZi
+ ht7zt0qu+AlxFXZ5Y9rC3joPYzoVgMH6f0h5
+ WItWvGHQ8gBQgjel7ZAKVSAdinYcyvXyh/g5
+ XQ2xwbDHi/Gx736y3SNW3Ivr3vRRNQ/ORJgt
+ SQ0ECCQbhRryNCz25SlDDAxbs6w= )
+PO4K5TL8FC932CHVR1339QMSVCG8TFE5.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 Q373J0K0LKK0NE6QLDMCDUMUS4D7N9DF A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ cz7WE3bqo5gy7MGC+CCp5rQq2OmWp1T0fb4z
+ SA3kxsMIEh8CDG9B3ETauKSvBokyLHT+WVC1
+ z96F1BiIM+ZDey0IYRDc3EGYhNBgdNGGan7N
+ GvyGpzTlwhBZAZNvn0Ledn9W6dI8DLBWEIbl
+ LFaBFwOGseR2VUp2u7yla73QTP0= )
+SEF41HBES71QEAB5G8DV253ODMLDJS10.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 VCVTKD7HV5II9DCBRH6O7O0FL9NV6O88 A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ SWIZLy2XlDbDRqN7UPOrWMxnc5MHzfw12I8A
+ VKGdUlXhOVcVEwVVAk4A3bXihVMP5gG5Z6WU
+ sLYFe5TOBmz66OjRmGNVODQNHpacdHeDvjQo
+ f3KcbWbl8CGH+uLxjGGkTpZ8MhJ8vm9w9cBq
+ urAsJbO1zFHDJi8zi9dQknmfJcQ= )
+VEK49TJCDQQ7AFSAH0A8MMF4EPP0LVFE.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 0J3ID6U2GQUPOADI9B867SGMROP8U4Q0
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ bSvFoFDIForjpYjxvmq7au1hq0oyL5mSC5zl
+ V/4WXGT9lAYk7wOZUA/8jsp0BGha9deH0G64
+ fTAfxt0OOuwibgqjXOEL9ioJ+xjk0ut1YQqc
+ lLenWNE7986fNLKihLk6CTIzXDRORqOp1cS/
+ 1ZmeKTA5zT8oM7FUwGmxPYLjozc= )
+S6102U94KPK3HL2EEB1KU341JC2EMML8.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 SEF41HBES71QEAB5G8DV253ODMLDJS10 CNAME RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ LMpezs03lkHxNunfHXUIqt5nOhUVclymGgvM
+ JCqFIDuUyhi6pcOPm4lxK5uPjxl4H5rdBRQ8
+ k0H3Ms3a4u0/wCFVgoZxsmxRBKuuYg8Hy2DY
+ 1wA8xshYi//tMqpSfaPn1qWOQ4H3Lmk1QQ9d
+ 7oS5xbj8LbxgRy2nHIMq2Tu/PLA= )
+VCVTKD7HV5II9DCBRH6O7O0FL9NV6O88.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 VEK49TJCDQQ7AFSAH0A8MMF4EPP0LVFE A NS SOA MX RRSIG DNSKEY NSEC3PARAM
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ KtSNurYbgzIR4o419h/wdNPJmiCe/N6V8Qpn
+ lL5L/ZE5JqnAq2MKdybxHpSwojGR2pTGehMc
+ GV5NEWqyK2TPN8f9stwJ0bH6N1/ab5iXe6Kt
+ F8zHjWXMDt/dwtKspsTt1crkXaI4qduta4Rp
+ IKoL0b5PqVr3vA4hvwAwqgYe/Zk= )
+K3MJD76QQQ6H0RKERHB88S6LHEHOMJRV.example.com. 3600 IN NSEC3 1 0 100 8B3F579FA62A6CE6 N9INKG4137UMU0NL0U8V5FOTD66UJQIN A RRSIG
+ 3600 RRSIG NSEC3 8 3 3600 20110331084524 (
+ 20110301084524 28635 example.com.
+ zyqm5HgDE1CUqpY2D/UcceQ7GmJZvyZn2uWd
+ 9S9/As+NIp/Pf90E6bnhpPu5Hn6H34xubnKk
+ G7qH3IE8JcohHw4zRIv1kW4u0CLikBbNq+1d
+ rDkWz/FDjsV5QR+nxLlaGwkO12wgDQYSZwNw
+ ja5DoRdcCKz2T1jKcQ+NNr0j0Cg= )
diff --git a/samples/example.com.zone.signed b/samples/example.com.zone.signed
new file mode 100644
index 0000000..851cc13
--- /dev/null
+++ b/samples/example.com.zone.signed
@@ -0,0 +1,571 @@
+; File written on Thu Feb 17 11:19:57 2011
+; dnssec_signzone version 9.7.1-P2
+example.com. 3600 IN SOA ns.example.com. username.example.com. (
+ 2007120711 ; serial
+ 86400 ; refresh (1 day)
+ 86400 ; retry (1 day)
+ 2419200 ; expire (4 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ 3600 RRSIG SOA 8 2 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ T8PgPaLsdbkEfZvPHPvYV08y73yoEGqQuLOl
+ db4jvv48AUqt/Q/6dLMcWz6lpFDCEyf/9aCl
+ XVBhS+PAo3ex8lXye8MIyGvh5/yGFUveDHRM
+ TvigNYz3iJnJj6aK8nkSM29DUe92pkx2m76O
+ sT97uSoh+8FX8Vz4qRRBD6NwVIQ= )
+ 3600 NS c.a.example.com.
+ 3600 NS ns.example.com.
+ 3600 NS ns.somewhere.com.
+ 3600 NS ns2.example.com.
+ 3600 RRSIG NS 8 2 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ U8RogXPsS5rAUPbG0d8Wcvdk2NJ5ccvK4pda
+ jEfvIXXgZIib3T+gR+PwDuK4sMV2rQxsmcrr
+ qz3Vc15SQhyt+DAXVsrTojT8iu0NJXEZSr/H
+ ntPu2/BfVcHbq2wTu01QW1g9/ub0yUltbkcv
+ Mt8ZGiIyF5AoChy04SmZVlmuHSI= )
+ 3600 A 10.0.0.1
+ 3600 RRSIG A 8 2 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ RXbKPkFlSJLiKoliNUC+tlPKru2UZfdksz63
+ Jdla5qf+prYU5HZlvMLD/Fs3dSmK7vx5S6gh
+ 4pzWAtI0NZ7NoHSsxk/aztoASeal0On55yCt
+ 9lXRQ+Avzl7Z41fyFTTdu3GF+tOfAoPuTegL
+ qDLokpWQTRfABy8zFIQvVvLWAHY= )
+ 3600 MX 10 mail.example.com.
+ 3600 MX 20 mail2.example.com.
+ 3600 MX 50 mail3.example.com.
+ 3600 RRSIG MX 8 2 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ Skb7nbpNawsKpBZBC/4vVXUxioxbrPggr+Pv
+ EZzxrVcZN4PNL1vLQxWLKaZf9p0VWjFUh6Y7
+ pyup5y8kL/y5PBM75jTIx+L95FlnB+Cef24c
+ z4f5eqGTteWxqBhp25ZNGNxs5lI6wWJkIObU
+ 2PHjtoZyXEGcYYQHtC5LQVQndbI= )
+ 3600 NSEC *._tcp.example.com. A NS SOA MX RRSIG NSEC DNSKEY
+ 3600 RRSIG NSEC 8 2 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ cM0Oa8GL61RYfdbLp3P6dH0gU2Yp1hsPvpkw
+ IBCcJ+0MNbZRxCTBnMBxt6VyBBAu9PPsTkgN
+ 1TdFmu1kD0fBP2bYAHrVg7xul7n9xoCKhWhx
+ x5Kj3bQCKlWL1AfhdH0fkXGyY4D8ufe4yItK
+ svm1y0TsIHnXO8aUrh+DOxyp4rE= )
+ 3600 DNSKEY 256 3 8 (
+ AwEAAbns20HerHdgnwqTXVG1a3764I7hVAzp
+ ahf9AF2dq+f+/aC8CWwow9BxU2uUSxDGj33c
+ 6LQLaJm9gx1y1o5lB/0iM4Oui6/xfx4xi5vR
+ SRE4fWPnWexH8SeHQgQOaq8ALUQGwIQ1l1bP
+ lWNKDg8AL1ohQERLQf0Skpgi9psrkPNR
+ ) ; key id = 46476
+ 3600 DNSKEY 256 3 8 (
+ AwEAAdC9GxD5zDPcTe6UdoZp+rm9EdFnV0mI
+ z/zFz8qRop9mLq/QBFaYsjpQdOahHQgk5FtH
+ OUywUaDKCorZuw8dH4iWpt/OqW79l8KMCNzd
+ xTV9Qky/ZRwO7Le/LbhsYgzw6eSE8d1xOUrb
+ 3w9PL8Zn5/059TE4yjmO8W73AZakgMtL
+ ) ; key id = 20058
+ 3600 DNSKEY 257 3 8 (
+ AwEAAdA0zDQsBM+2/OI8I1lAmAvdf8cB5jiS
+ wyyrjRjpWHlMQYiNXNTigb7fZdTx1SfX05Vf
+ yERfWy9ACRcssjf47rQLvmvE+sRAP7mOaRIY
+ 7CjD1kQCTYf3TybqAX5/MXZbl5OibvS4hpjj
+ SYO1lg/tITefq/Z1JpNUnyzwiuzQbu2MUytv
+ qqnkrVIBp0AmPenomFmaJ7chi3s9TMrkiBvc
+ 58S5a3jEvQR/U/B6hw1ruCP6EOhBg/KHApPn
+ eVHeMCtv7LLf1+xNQ2j6k3N5sCXQ89EooLO/
+ WNsrCmbQE3zpwZsa7pCC8LW7YQowTtbjOIhZ
+ DsatvWPhGGUaCemoTt2ceH0=
+ ) ; key id = 49540
+ 3600 RRSIG DNSKEY 8 2 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ RW5kvcZuCmlM8DEb8teYpTRv8BCT87cvrlv2
+ eJHlnIT03wjUVJx5pLr9gYrL1fjua4zGPLc6
+ 8MjssdVoiHbYt7pZ9JVnGgrfTSMW5emkyu3+
+ FazMDmCpMhy8GN6QyUADS9c12JkanNR+ugwW
+ i2IuR6VSZbBEbgK7wizdmu3yt58= )
+ 3600 RRSIG DNSKEY 8 2 3600 20110319091957 (
+ 20110217091957 49540 example.com.
+ AFg593dFrLP8EWKnKVQCpt+/rufL8mCTe/Ks
+ NozsesatF/B0LXkztK41wEFczeciTJOMlqcp
+ tbuaTUyiC0Lnz8yzAt1PRRxxZrjr8CVbwHDn
+ SodKElpfRA9MEFHEvphD7s8gnzCEVCQEw2zo
+ 8IbDapCNAADx8pDE976/ixKWca1XNbXGUUwv
+ LSKZ/pbNd4FCd8DqG3B7vcmVv8k5bGcJXdlU
+ v8OlI2rJXr9yVs4Tb/LgncLcDHOHg4TCKE5e
+ ssQ3qnAwC+PtJGMl+UF2Ar5Ue2JZXijkcgxx
+ fYYqB3yFaoxfn7neRE5CdALY+kMwv9ySkXWz
+ 1+D0NCjZGKIdnZCAcg== )
+*._tcp.example.com. 3600 IN SRV 0 0 0 .
+ 3600 RRSIG SRV 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ SZqwbOWOrGh0PB0st0OwVICwishDYIwM/VE1
+ 3yp3/WboQFWESfrpv9QOfPD19yet97Zi17C/
+ vQ7YifNWm/pKHOfvlgAMd5Y+Vku0Y7W85M5j
+ SsqjfDoiS6jPWKtHswVq8MRHIpRrCyLY7ZTM
+ fGp2A9SRGTa/vFyCgbvu76ampbs= )
+ 3600 NSEC _foobar._tcp.example.com. SRV RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ B7lFuz7YrWCvuTs5wb0dA7a+FaKhzQnOYSAr
+ 4myC1mVFpRtTsk50n/NkUBTSDBoHjfDdlYU9
+ DRBBct0PZTmRRv5EX0Eiw1BVs4mDa7WlYfFq
+ Xkc9nhY2jjOFbt8HTLsOdAahXV7VxQBHn8/w
+ ewrh0BvaM2Z/r4OHUqc2DVsgr2U= )
+a.example.com. 3600 IN A 10.0.0.4
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ KMwO1EvPdjDW7LJaKY85TPtUogFWA4IWQPvw
+ SKNX2aADOanzu/gnY2tVOhDq7mWJ9tQXlMtx
+ TwsAzcp+1PdEKCUjEBC53YQI/L1s3opKBl4S
+ HTLgGCKw5KhcALeWKGVJp4bbuuDFzmkpP3dw
+ DX41E74bR1qFeVofwcjuvQw45hw= )
+ 3600 NSEC *.a.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ p09gsGkMo8QSE1ujTblgmpKqaOk6X5RXsIsi
+ 8oiOgpNiMfBIMAYNd4T8OqyAEoygvkqw4h/U
+ GuRSlSI1vFUzcsua+lVd9/WfbQ0gjWw9zzGL
+ rfku6PS+skQZPfZhkTh+a7TnUwoHb3K1sY5l
+ tM8Cph4mXhHJbiqxdAiQqjlSj7k= )
+*._udp.example.com. 3600 IN SRV 0 0 0 .
+ 3600 RRSIG SRV 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ IG3bi+NqZUHgSG0qyASuEc56z9HVV1/TMCUM
+ dMTBMfsMzG3LqI3qonhRGPelb9ELDlowKnXC
+ joMXetqLNPpsFsc6tO97yxmkDfAskAFpWmUu
+ UQ5lG5crlwJ+6PiVANXtrNNZnsMp/jiDFOoV
+ b7FrF48gfkt/8E6Mzq1nYKFn67I= )
+ 3600 NSEC a.example.com. SRV RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ mQxN2DLH/YEO2bHnvKaHqhfJYkx3HHgqD8JM
+ fRbcRX/YDNY0oy0b7VNfN1J+4FYdCZ8r60eb
+ 39dFigjiSEXNXmi3SJ6X6irqv4ZOXwoxtjtk
+ CzQV5GsKXnERFcQ5SsCwSbFNik2R3gb3kYuW
+ qqvYpqPSVA+ScJ4cdNXODvL9zag= )
+_foobar._tcp.example.com. 3600 IN SRV 0 1 9 old-slow-box.example.com.
+ 3600 IN SRV 0 3 9 new-fast-box.example.com.
+ 3600 IN SRV 1 0 9 server.example.com.
+ 3600 IN SRV 1 0 9 sysadmins-box.example.com.
+ 3600 RRSIG SRV 8 4 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ jIA+72DXdYMsWQ45Sv2MBg0rI3rv/7oEqoA0
+ rJ9X4la9o/ozwca7CJE8HKP6l43gzns1pfZ7
+ +QsYW5BJOOB8ov+cCEVBW9XY37naNa8fKUsK
+ Mpzo35gaQ1zi9+FnseAwZ0WAicl4+766p4iJ
+ MzDEZA9VXvSMq36i/v8c+VMxFP4= )
+ 3600 NSEC *._udp.example.com. SRV RRSIG NSEC
+ 3600 RRSIG NSEC 8 4 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ npUQV7MbigckrB6D4jshTkGpOvZY4XTulYP1
+ EUjN7Ttr8i56UEon3zzVY2ZUK4McyNrkzWqg
+ KPoFNG8xwf4bI2+WxdJeYo45PPZsy6bDTbMu
+ lYc68hQ35r3ok32SPG4GMuV53iuSJBCNrM9o
+ Rat/FL4Qoqzy+sVk1+tnz2ShzqI= )
+*.a.example.com. 3600 IN A 10.0.0.5
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ iHMA40EdVEV0HIxDKbxcOe74roa7X3Vi+lpr
+ XGJWx0gbVVhMsGdXi8YycbWAyHvwxImiU/VT
+ ZcDiDExzH89XZbzmEtP5vjAOBaf9rQu7cFzC
+ mAekgEEccVYSt6QLJTxcdk97CDRNkbU1kd02
+ J09lSSyQL8ATADXIlWFUfMC8Fx4= )
+ 3600 NSEC c.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ NKYN+2bmtp/2Bfic6vBqWAC/ouTz4qEUgdw9
+ a153VST6W3UpROG/xiKV/STmURt8oYIzHy42
+ UDRp8DmuVRMgeP7CCCYDmFq1+hSHv7iia79k
+ bvrSqdEbfaAjBkHMPlJyd3VjqKz0L+Q7sOKP
+ pWKItsBruF9UTJMP0Y4WLCvsD1Y= )
+d.example.com. 3600 IN CNAME non-existing.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ KFfbRqMSwZOtr3plXJ2E9uKvEZjop9wpmq57
+ EXq4Pus6pBhdPXXgwDo9/tDsTj6woScdlWyk
+ BsDYRIVfcu+jBbyTdFYSg2Em2A3XwtTxHD+s
+ wL3cRc7uKHs/FsWDVldxvrKy/ljX/kdmkiHN
+ xiRCWZsPa6kxB3/KtDRjYO6pkCM= )
+ 3600 NSEC e.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ HbB+j61LK2AzrGmeLtVFRI4Ee+9dkh01xY44
+ AHWKIEqqxRA95yOxWYDwVXXC4F1cO/UN0nAs
+ pTZekW8qb3vGrBUytno3mYZST+RHN8KcrWwL
+ n0nXsidEekA+ZGxRw7eltu8ECYX71C56bqp/
+ DIilbcD1+bIyGxFHlYN77l+nVUw= )
+e.example.com. 3600 IN DNAME bogus25.com.
+ 3600 RRSIG DNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ SKLwv2FArbnNXXjaRxHsw3YcqYBxPNL/EETi
+ 6rKHVHHOgLN/IwQ6wLtmXZfRSV3Avw0pYmgt
+ 6hVda0mnJ8M4BPRal3z2cf9+PVX/f9kJWUNM
+ h1A/ibKKIwrhcdh4Z9s7QXGioE6WiEViG3zP
+ pfkajBllmOrE0pEH0YX1rWValCE= )
+ 3600 NSEC f.example.com. DNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ swVPAYAboz3U8Y2Jcil1R6jUIAHggZlrs8I8
+ ky7EAQTFYDRhLBC4UeGO+6DpkHAKCGepd2E7
+ yojy/wttp4VhBxcaDGidc94z59Km/wuxF9Yk
+ cCYv7Ip6qLpk8L4CJOJvkFAGWTpkOYkA1qDR
+ tQ1IMSOsc6s1xaY9pd4vxmZkS4o= )
+c.example.com. 3600 IN CNAME c.a.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ hlO9jq8fIGbacLj9oYvwwyz65+z6ttWGg0Dh
+ wel26v08PEEJ19wVcZsXwiZi5ey9xaNG0OfC
+ z0xeH4XCOYaFGtKjSAqpT1FLGmcFOqhbGP2+
+ 4pxICNlMonG+w/p7YePr5jyDILbTbUmp62Hc
+ ZoV+MVNvjFpDbxgHvCpFoGZguqs= )
+ 3600 NSEC d.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ yTCDrpHhmnrwD8HxGPwPAXCmCik9aFyfESjW
+ 7bqrVgo8/pH57JJxGw1FVdoP46+ba1E0XRmo
+ zBdKKjum19SJBV5rzTFsJ58TDxsIeXWgwZgB
+ +RKY/peVIEfhuBHfLhdPocWB7rrk0dCDsLmN
+ FbmhtNkmXs9CKLYv/ucsXnEEyYU= )
+g.example.com. 3600 IN CNAME www.bogus25.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ PCl2njNFV8UQjnI5C5QUOE4IPETqM3orSN/e
+ B0WhX8QRvYRqJgayP07tjgaslUIzpAWo4t/J
+ +R1bjfkj4w0Kxk+eABUgyHBq4Cd1EO82L88L
+ DVvrDAXxg7Uw1dkeeN8y5ZuJ0tK71AE7XJ7u
+ YdTpbi7cfwcJuhRY45NbZDVtLd8= )
+ 3600 NSEC f.g.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ zVhwl4EzpNuLNvPr5y5m8hIZyjhMzHSMNPQz
+ gMqljABxOeeNw3r5y9NZzm+6vczJVuJstrzr
+ n99bHnis0CX9QHZ9JMyZM2+qDLqvFccjAqTF
+ TwZBRhYODrI6u61DiRPCum8J2sIiEwIOVW8a
+ cDosel0Kz5cckjLJmyvew+vI2Hg= )
+f.example.com. 3600 IN CNAME e.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ QLcICtoOCD6eqtqDlawijBoRkruFxtOY2lv5
+ nrkQoZa0zarM4Y8Zs05PPjMnFYd1kVgDgzNq
+ 4RU3jd0bMM6vdFBDfg/HV1OK98nvA9upuFOy
+ Mn4Ll98aSkZ9rBW2nHMK0gxClGZBRSU0983v
+ +vcSrrwK/Xr5MLYzJPCyMzmZjt0= )
+ 3600 NSEC g.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ zWPwHGblevq/icAJ2PEB/Vrexdk78ZqkQ4fb
+ sfKxqHXoXlXvXSTgMd+8jD83rpCwS9ju3W1c
+ XF0qcrw7kWVDsjuZB4ynustAWXFa61+S93Tz
+ clXNNb0zRFFt/pfhMi/6MG8VL3lPZ3seRUAH
+ sNqUj9cD8J3ViCJ6S2tD0EaWdqI= )
+*.j.k.example.com. 3600 IN A 10.0.0.22
+ 3600 RRSIG A 8 4 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ AhY44yY5dbyJvWFfEjxhksL0Jr2hGy7LAwFS
+ nM1+xeU40Z4+xB+6NEiwu+aa52ylbHkGyp7W
+ seQ0+8DG9biYIFm4QiEud/jQQIDEqYk/oVVX
+ +aJmTYsJbZFVmffWK5oG+/ncP/xfLcnPQ7Zp
+ GAvKgnnxSr0B+FNsFGwFrAJpyy8= )
+ 3600 NSEC h.i.j.k.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 4 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ aS+Z3vh9yrxVIk5w2t5SfuSjY52ylTaKCFoq
+ QP5WiZ+Ce9K9E5kenfU3ugmKxU2Ocwl7491G
+ 7mYW9ZxfBRnqoA4WZtszDL5g/qGNS0UQm2q7
+ 1tVkBQlMt5vXQO7e0mK0upZ2Y+6mllgvv5/x
+ EfICd8LbiJuD8PqrixsiTZRGzXk= )
+f.g.example.com. 3600 IN A 10.0.0.20
+ 3600 RRSIG A 8 4 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ EEOBQ2O31vmGHuj86oLBL5AmFAV7nVVxPjxI
+ +Xvru2Evbm2HJdZalcB8YwrFEdFGMpoxLpXo
+ FKevq2mGL0CfwifSfN6Z+lU6/m3JZQ5ugzXz
+ c6PFm/KDtCJtWkNIYtHGC4flj2rpMNlJ4ERm
+ /U/lfDy0PwPQ0QvYXZE8imXQsjw= )
+ 3600 NSEC *.j.k.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 4 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ knCwO1mKW8GKZr+jq0zT2FwlPwoK58GgvyGt
+ wvJmotKlu0pyYvVXeibowOxacDRx1SZA/Zue
+ nkA3dF83GWygxg36WjH3lyN+yaIFkuXtKYFH
+ nb/F6tIT6C26gnBJfMBKxm5mh6DqncIMFIad
+ p7ohHb/HKjj0CbGP55T6NV6OJdY= )
+*.l.example.com. 3600 IN CNAME c.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ bj2qkiCFVKzkmLafxnS70+gzkTErQgsJK1sl
+ SAxObFbBfG9eLGktw64k5XNSX1gK8cswj4Q0
+ d/XkITXMf//rVgyRSXFkIRdalhW9VlkqNHll
+ muF5PQF3bqz1ec3aVYJoQJurnjKj9YIyCzNm
+ Y5gjwqB69xzc08hUM57WwS5PrYc= )
+ 3600 NSEC mail.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ W5qj7ZHUIii8CR3sHkLc6ivln+AFK4SmxpjD
+ tgYUCWaUd8Y/ahldOzgCjzFY+I+hrUCifd1G
+ YLr0WtlNe/LgF9JhbiuIFg+SViBnLJzJAPR/
+ yTr9qENKWQABvhmd5CfCsUAW/r8q5d+q4/9d
+ P7DfCX7FosksTkOuO5qSWFHiPAg= )
+h.i.j.k.example.com. 3600 IN A 10.0.0.21
+ 3600 RRSIG A 8 6 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ IfqXe0py5ug/bM3n+L8vIjgyEF+DPCkWZ1xj
+ LmHAYjBHW8fBnByoYNwSBayXJDzpVPrlGiGB
+ u7FC78yTqNeeGKgH72D7JgNybpEELpHY72+A
+ uYKOgizlOQn+172h5pmQcSNZjfRPVtK5wR3t
+ /ZOsz44siyNR3+TQEuDTnZnS59A= )
+ 3600 NSEC *.l.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 6 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ nTUAjiYPw6Gj+V+uz7gW27lYidi7Jgu1rTRY
+ 7GGZZHZRaFtoeM7ymSxZmlOdKrJxsjIhpXOC
+ ltU9dR0PJo1OnXKCQPrLjK3nIkNfGVcJU5Xj
+ MfNcdW6T1ursO2uZ7lrTOgBhSTxNNqiXln1d
+ HLwy1lHgTqNGg8QvdsbT1ixR3uE= )
+*.n.example.com. 3600 IN DNAME bogus25.com.
+ 3600 RRSIG DNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ gcuk3osH5dCvM2GgfVEogCuSNIQgQFAc+hY1
+ igrm4uTT9Q+xrwRTKVqyaIZs/TovhKUS3npB
+ 4noVLbGJIlguztNvIgaB9wnam61NaFnBZRdW
+ 1guOnkExhSe/dTBupdEKVAw0WOrAOLlt06Fu
+ TFAAOBNo6384KB3aZ1RrKUu4Cqs= )
+ 3600 NSEC new-fast-box.example.com. DNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ wMenqM3A9lWwZSHJz+7t0hBfTsB1JGK9qV9F
+ kGtJRNl0SuZA28bFRL0J5vSKj9tuB8EjCRdW
+ 2l885yaKKGSTF3aFzDnF2YW9mV6BadNGwdkC
+ +mYguk/tkPNW2TMdrYJC7StXKh8dOQIpT6/K
+ oc+ShVBYtQJocRy89hk9M4Ex9EA= )
+mail.example.com. 3600 IN A 10.0.0.3
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ ah9IQBB/moRnqRL9mug+9cEE6Pz1YbJMQkUg
+ yzTeh/09bh3POMn9eZqo5bBx6vlDsFgUbw6e
+ IclZY4rV4mUeIWz2kEW/ZHc2tADDYVHRTQAy
+ 4sy3g+tF3d8OxMQZ0v6J2MTN9DlpVCaxbjPp
+ sd0xjJ2uBmn81DKbaZ8UKA5ND1E= )
+ 3600 NSEC *.n.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ oJMJsjzzNWihix6CeVihqCI/ByqU0qm+hDWX
+ mvgss0U8VXQ1o6oUJ2kXB9agzhRtzo+Z/5jU
+ 6zFYajcnzuwD62jmLbz5NAzcyZX+ejyHtt+d
+ /wlkYGrumY1B4qB0YGRji66Wo68BK11VZ+a4
+ hjsW6qRyHsQeKus3BfdQ2DRHU2s= )
+ns.example.com. 3600 IN A 10.0.0.2
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ Lx5lSuiEjsbXrLW6PVIkoojgWfRTxIxdbVDv
+ 8lC5bUziKm41NQ0AVduIY/c08fBshJ83ylM1
+ GqsZKwfqSszMIlHu3u5pONkMsYs7lxxYBdES
+ NZqEsTsaEmgnMlv6BM5cvstiJKVX7+z43y9j
+ XohTZ3G9UOv3B0uObMzabqweSfw= )
+ 3600 NSEC ns2.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ rqlsD5SHTL9sXqlqBU/ZcAxn9pkKFZoRjAiB
+ kgdU8vExku+wGRbBB+c0toFbmPjJv1E4z9ae
+ fN3dfxCmIg049UspJUP0AqWOrtbQqqN2d3dl
+ ycJRw5Cpf7qOpp41EGJ/ujPzeIq6t0nW/m2P
+ JGkE9arlL8J802tFJKWn2aUc78Y= )
+o.example.com. 3600 IN CNAME a.e.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ fjrWtwXBv82jZ6BWeYlfxLqxOvaZNONWqiIF
+ 6p3NM4Nwv7O1BvI+Jr9MzxAkk3CkTynGIFQc
+ 2wFDrAlT6XnBjJmvNiGf45utlhkifEYOR2Vw
+ qR1O3o3x4XMc+gVrmhdMaYAabZnD6YYPEybM
+ 6dLzSDMg5K6GjLJglmimT0wfTcI= )
+ 3600 NSEC old-slow-box.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ RwVHMNAd0Qdcu85znEzuhPF47UmoEZ0uBo0M
+ jd8ySEH07eV0lg9JOpzvdo3gUD6zyYs3xC1S
+ CO/RcTGIhEAfvkhV1N4/S5eQzUn3Cc5iaXUG
+ WQNpYuE2JKaLr3m3iGmxO2JqkE8YqTyK2WEf
+ rAL2SunFcKua1KHX959yNFGtou0= )
+new-fast-box.example.com. 3600 IN A 172.30.79.13
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ aeEl9FNzWG3QAPjDjCTZNMpO108nKfRqB8oW
+ Sw/e6Hynq4XKQuBBKNCvRBujuyrPMSuJdV1Z
+ xc1MGKMbSD1ZGyROhW+F1pTyRho1f3V4gmyI
+ 318iZuKxy+IbOVimYxXggM2xgkBgROOVI7r8
+ slU5+SqZ3c/DfJn3cVHuevAI+wo= )
+ 3600 NSEC ns.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ KF7gy4yC2SLwJvhCr/wBiNDWO68ypNu6EyBo
+ SyFnP3BsoZxsZvz3PYnG+slYAfMYqxfZAnEX
+ p8qMUQeWuZEzZLqmDw4/yrRupzjLDFE581vp
+ LVjUxYANKjOvYPbn+bPsuLKG2BuCcpyjLeEb
+ 4GrR1PBI6tRPfIyeUo1AUjXzlW8= )
+ns2.example.com. 3600 IN A 10.0.0.6
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ EjnIln97zP0GlFiF8J9HUuGBohcqvaAnCZUf
+ u9RuM4YhAijthrv+1vYJj9IKLE7JGXesVXcW
+ 6iLsddK05EA9UWcKhyOWrSIz2NmBBo0lj8uK
+ 7K/0zAvJ4uiSU+/CiGJBmzXxAQzC/gH4mU8k
+ vdpB7AufVUaKGDkB8203wk7LeiU= )
+ 3600 NSEC o.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ cOxEjb/Aje8DI82rY7qNowoJ2VIiPOZIhlfr
+ MJMNDEiXBfbw+x53ewEj+YpnwwAAFWPrATtj
+ C/pEyxGCqwxEYkUCCTaM6YjhAKR0yPVJVkjY
+ GM1frct0/uOUuowalGf1SppZsxBKqv5cGq8o
+ x8GlBRNWt02ElyO2Wyy9k2TjKR4= )
+old-slow-box.example.com. 3600 IN A 172.30.79.11
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ ON91+7dJR8dAN2SUBZclVbrhRX8BOU5HLRYx
+ J8Iy4kiaPMNdLEHqXF2tK5FqSLKkZV9S6k1p
+ 5Hl1TUGYxVFq1+OxXpYzgk+Wy6QCW/sxWNky
+ ZpZ2X0ZzicI733kJ2YTZS8F7GaU053tCwOmY
+ wmLMKa6qd+FNh/xGLpUFrG6xRmo= )
+ 3600 NSEC p.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ LFwXMS6XtokUOkda4DcVgSTNpuO2dhzUMbiu
+ LhfiYQ+nXn3Qwx0gORJZNdcMmUn3/j8dV/MN
+ Mfdil66OwG12ZNfi6LvLlj8DdMsBie/vHDLR
+ oUJUXdeQe5sM1rU+QoHfPCBXMWv5Bp6ZV8Wo
+ Bw1ASybab+P0JXWzlnKkfzgBUsg= )
+ns.sub.example.com. 3600 IN A 10.1.0.1
+sub.example.com. 3600 IN NS ns.sub.example.com.
+ 3600 NSEC sub2.example.com. NS RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ HjalhqyrN25GoPU0znzhzh58b7nM8N4mLKsE
+ bB+edEZOkM15enAhMeKzYWtUau9DTWwUC3Ip
+ DeLUT5XKEm91Ln0UnK7GKWfSPfVyTrpNOpKi
+ EnCUpk9yVC3OKkYt5jCTlP5HjuLRh7IJLpfd
+ RPtrJqJJSNmHt2vFoSdMw54Z1Xk= )
+*.sub2.example.com. 3600 IN A 10.2.0.1
+sub2.example.com. 3600 IN NS ns.sub2.example.com.
+ 3600 NSEC sub3.example.com. NS RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ NdI/fYvlY5BQsIU98z37XRUtoYL+3d6NJBMn
+ erxI0rDgqceMFVI52Hl2POzqanYoqK9QEyWS
+ 9rnt6pKzCG3vZv7XcdyqFkP/sIoMNcevZw5/
+ JJ172wyrfYRepkbQ20CL9KUGOyQaPJQs61wR
+ 1L/78YmA8QD+zduli61hwDRjN4Y= )
+p.example.com. 3600 IN CNAME a.sub.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ DQQ5JhXp1OUOTm6+Rtsb3idf0iO9PvuASLwU
+ 9tzKExU9piaTE7FQN95fq48Kv40iH3W7513p
+ JKbojGbZui2OR4l4V0gqDzP4MU0fhMi+kmt8
+ oKhEY7FlOx09Ei9jS0wWYBnPAxIm5N1NSTbP
+ g5tQ7MWYtBNtyyrN9mSdicAaCvw= )
+ 3600 NSEC server.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ LcvgnVSYj2bojkEPkHopvuwg097SLoVYVzDe
+ N9M4GbHYkPILrdevgmmNIhDw7FS5XJI4zVo9
+ xvE+bUMK056uT+DmPSCJh36q9gt2bteSxbqb
+ yus9zWldGoUoQzwuvtWcjHwPtSnquL/16xUJ
+ 3FPwtqNGKw4Vx6zw5PXdY+jRTcs= )
+sub3.example.com. 3600 IN NS ns.sub2.example.com.
+ 3600 NSEC sub4.example.com. NS RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ QKnEmC9rfdkdEkLLKxcnm0EkAyW1QI56AuTG
+ +Mf2CoD+JHgf9dFKm9EOinM+pHcrlT6/XmUW
+ H2IKnWcoqs2B9Vrh9CeC9qXCnFxaNxgMG9hu
+ zg4H6LCW0pSKOoq8/KPCrtGGJTn6k8ck+qhP
+ hoz2O63tHuIpAtO6jcFL0B5jk7k= )
+sub4.example.com. 3600 IN NS ns.example.com.
+ 3600 NSEC sub5.example.com. NS RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ pFTM518iEalVbWIisYeXX0mfel5D3EeKL2tV
+ e547nz5STOOKeqhaFpwiEkBnvBvbUJLDpNJH
+ bTpR98BDLnLPhSuhdQy1uBhONl6vaI6o0+P1
+ 2cDaDQWat7Qc0bt2FOjWfhwzEJznqUvHFW1E
+ 3umsEPEXcHR4fmdPNnpvCnuCYv8= )
+server.example.com. 3600 IN A 172.30.79.10
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ ptyuguf9rHSyP8q4a+ob+kNl4ns3ZNzOT2NZ
+ +9lZsqpbbe6D15/6AVZyEz7NjLsLbSTbmUxI
+ MKacxVRUbJS1vQ7pztP/Lms4W+LsmnXafH0d
+ Pyj1OpArqckA/zeX05RXizUfqmsWq5thTZZ8
+ VMsCFImGqpi+p3wr6FFc6NkuvEE= )
+ 3600 NSEC sub.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ Tv46nHdkqO+SBiFf3RtDnIbyom2qGJ8w+ftJ
+ EYNfIdIghrR45az4sE5Ax2OzbIDzDycJhu8i
+ dSaLEgWASatClQZvzysdqoVmM2ajD+MgKTpv
+ Djr5BRpLSQc/qfEINM5lus1Gy1UNruhYc7XV
+ ah4fr1LXSrPGoo3bPk5r9Sy2VKI= )
+sub5.example.com. 3600 IN CNAME sub3.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ AP1MAgDTW5UYOQGZe1kW9qJGNComeMgBtQtK
+ PzsIU9y2TyrcSbU4wB8JRFJ1hMZk5wlkUe5M
+ yhvKe55wvknSlWOR1AU0vks0kSzhoPxHPxEM
+ NpMBV/Dv7NCGivh7LMxr0ra7EENNr4Ojv1Bl
+ bUAj8VMuLir8xqv5z3LzWTEVQ/g= )
+ 3600 NSEC sysadmins-box.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ u+ulC7UqLA754CiYgKQHXquGhHHHoF3SifcC
+ lVHj9OTLXomfJMDJX5UG5K3yODlokaYVWOZS
+ MDus3B0LdAVv0+rEEPNxVBZ+t6P5/4JufESK
+ JFvxL3pSIU1bIlUZ4VDzgg5h6rBnA/oFavCc
+ a8xgf6FDwRNWVxdWcSfH/dStCSk= )
+wwwtest.example.com. 3600 IN CNAME www.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ GNh/COVeSULHxFcEBE66wv56YHNAWsPuSF7C
+ Cl2rc0JXlOCDhUqKy7ZKFTbXMZi++upiHpwI
+ BBbYLb7mhpLr/zEaOJH8QdiHsE7+hkY7oe2e
+ Gz1rvDyjx4XSugVXHr97RhZI7UA4opECDrIv
+ 5p3nqGLutSWju/grR6+keppEfFk= )
+ 3600 NSEC example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ sRklHhLmH7i22GH8W3j5N6qMrG0rEmUb2+d9
+ QJVcnQCgwyeiO38DMN2Vvy8jqVgXN+C5uRHV
+ XcvUhJjyJ7x7zaxVKvncwlRBQkGj5hNmVCoJ
+ 4gpVzD3aerZ8fwwMUf+ETqBtbkBajsfayEXq
+ kpITfSd4Pi5IyVbIr420IconoPc= )
+sysadmins-box.example.com. 3600 IN A 172.30.79.12
+ 3600 RRSIG A 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ ztrXayS9OAxxKPP2U6DxtU3VNQ+aauZXNB+l
+ lxhXm2j/dFo6j6eR1hnRfGx6UeauQAdeKQA3
+ OKeNaar6KbH9rw/iwnZbErWQurdUNVYvxEHD
+ fRRBa1b6d/zkwPcbdT+pSIZVoRzt9LrWQuEd
+ 2Gk5cBl6RP2oKxulDeP5XWXpQN8= )
+ 3600 NSEC www.example.com. A RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ D03U27J/Yoan06O1qYHavUBHZZapO/f0GR5j
+ OfNHxpEvsiQmekeJNtYD/pm3aQhXjn8GDh57
+ yrN6TBmo4tleL9M0w5BTT4Bm7yHdg69T+DgW
+ cVvgqv2Vgq/zbIYJuBd21doDh2LrkHcMbTas
+ FSYHA6OV8p6DzkbkXL9oykq/LCo= )
+www.example.com. 3600 IN CNAME ns.example.com.
+ 3600 RRSIG CNAME 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ ElzpT92LMJmKZq37lHmE6tOFDjh3RBdW3wRF
+ M63YsLhlP0OFNsbFefBA9H6qQdlV/OlP9QYD
+ FRn6hWPkuoelvDjyNdVFPc6CZrns4+eU34Yg
+ aGPZoKVszovHu22Lr4soJnDFwRAJ/DXcHMCJ
+ EHMSQpTYIg7AuDaBg9j+LqCVKZs= )
+ 3600 NSEC wwwtest.example.com. CNAME RRSIG NSEC
+ 3600 RRSIG NSEC 8 3 3600 20110319091957 (
+ 20110217091957 20058 example.com.
+ ycFBDZT3AHzyCklFxMheOfRyehNZNZsXHJei
+ h6Fi9AChB05oLVsM1MZqVQj0LPfZC7bJENtJ
+ XNwNz/wOJIjX4OUSGQQvEBLa+bzMvBg9i3L1
+ YduNOH1xHGYbYKvxUd5b84XsIu1VQdffWDoK
+ hkFCBPGlL+A8/5qPva1FFdk3s6Q= )
diff --git a/samples/knot.full.conf b/samples/knot.full.conf
new file mode 100644
index 0000000..04fbe09
--- /dev/null
+++ b/samples/knot.full.conf
@@ -0,0 +1,250 @@
+#
+# knot.sample.conf
+#
+# This is a sample configuration file for Knot DNS server.
+#
+
+# This is a comment.
+
+#
+# There are 4 main sections of this config file:
+# system, zones, interfaces and log
+#
+
+# Section 'system' contains general options for the server
+system {
+
+ # Identity of the server (see RFC 4892). Not used yet.
+ identity "I have no mouth and must scream";
+
+ # Version of the server (see RFC 4892). Not used yet.
+ version "0.1";
+
+ # Working directory of the server
+ # Used to store compiled zones and PID file
+ storage "/tmp/knot-sample";
+
+ # Number of workers per interface
+ # This option is used to force number of threads used per interface
+ # Default: unset (auto-estimates optimal value from the number of online CPUs)
+ workers 1;
+}
+
+# Section 'keys' contains list of TSIG keys
+keys {
+
+ # TSIG key
+ #
+ # format: name key-type "<key>";
+ # where key-type may be one of the following:
+ # hmac-md5
+ # hmac-sha1
+ # hmac-sha224
+ # hmac-sha256
+ # hmac-sha384
+ # hmac-sha512
+ # and <key> is the private key
+ key0.server0 hmac-md5 "Wg==";
+
+ # TSIG key for zone
+ key0.example.com hmac-md5 "==gW";
+}
+
+# Section 'interfaces' contains definitions of listening interfaces.
+interfaces {
+
+ # Interface entry
+ #
+ # Format 1: <name> { address <address>; [port <port>;] }
+ ipv4 { # <name> is an arbitrary symbolic name
+ address 127.0.0.1; # <address> may be ither IPv4 or IPv6 address
+ port 53531; # port is required for XFR/IN and NOTIFY/OUT
+ }
+
+ # Format 2: <name> { address <address>@<port>; }
+ # shortipv4 {
+ # address 127.0.0.1@53532;
+ #}
+
+ # Format 1 (IPv6 interface)
+ # ipv6 {
+ # address ::1@53533;
+ # }
+
+ # Format 2 (IPv6 interface)
+ # ipv6b {
+ # address [::1]@53534;
+ # }
+
+}
+
+# Section 'remotes' contains symbolic names for remote servers.
+# Syntax for 'remotes' is the same as for 'interfaces'.
+remotes {
+
+ # Remote entry
+ #
+ # Format 1: <name> { address <address>; [port <port>;] }
+ server0 { # <name> is an arbitrary symbolic name
+ address 127.0.0.1; # <address> may be ither IPv4 or IPv6 address
+ port 53531; # port is optional (default: 53)
+ key key0.server0; # (optional) specification of TSIG key associated for this remote
+ }
+
+ # Format 2: <name> { address <address>@<port>; }
+ server1 {
+ address 127.0.0.1@53001;
+ }
+}
+
+# Section 'zones' contains information about zones to be served.
+zones {
+
+ # Shared options for all listed zones
+ #
+
+ # Enable semantic checks for all zones (if 'on')
+ # Possible values: on|off
+ # Default value: off
+ semantic-checks off;
+
+ # NOTIFY response timeout
+ # Possible values: <1,...> (seconds)
+ # Default value: 60
+ notify-timeout 60;
+
+ # Number of retries for NOTIFY
+ # Possible values: <1,...>
+ # Default value: 5
+ notify-retries 5;
+
+ # Timeout for syncing changes from zone database to zonefile
+ # Possible values: <1..INT_MAX> (seconds)
+ # Default value: 1h (1 hour)
+ # It is also possible to suffix with unit size [s/m/h/d]
+ # f.e. 1s = 1 day, 1m = 1 minute, 1h = 1 hour, 1d = 1 day
+ zonefile-sync 1h;
+
+ # File size limit for IXFR journal
+ # Possible values: <1..INT_MAX>
+ # Default value: N/A (infinite)
+ # It is also possible to suffix with unit size [k/M/G]
+ # f.e. 1k, 100M, 2G
+ ixfr-fslimit 1G;
+
+ # Zone entry
+ #
+ # Format: <zone-name> { file "<path-to-zone-file>"; }
+ example.com { # <zone-name> is the DNS name of the zone (zone root)
+ # <path-to-zone-file> may be either absolute or relative, in which case
+ # it is considered relative to the current directory from which the server
+ # was started.
+ file "samples/example.com.zone";
+
+ # Enable zone semantic checks
+ # Possible values: on|off
+ # Default value: off
+ semantic-checks on;
+
+ # NOTIFY response timeout (specific for current zone)
+ # Possible values: <1,...> (seconds)
+ # Default value: 60
+ notify-timeout 60;
+
+ # Number of retries for NOTIFY (specific for current zone)
+ # Possible values: <1,...>
+ # Default value: 5
+ notify-retries 5;
+
+ # Timeout for syncing changes from zone database to zonefile
+ # Possible values: <1..INT_MAX> (seconds)
+ # Default value: inherited from zones.zonefile-sync
+ # It is also possible to suffix with unit size [s/m/h/d]
+ # f.e. 1s = 1 day, 1m = 1 minute, 1h = 1 hour, 1d = 1 day
+ zonefile-sync 1h;
+
+ # XFR master server
+ xfr-in server0;
+
+ # ACL list of XFR slaves
+ xfr-out server0, server1;
+
+ # ACL list of servers allowed to send NOTIFY queries
+ notify-in server0;
+
+ # List of servers to send NOTIFY to
+ notify-out server0, server1;
+ }
+}
+
+# Section 'log' configures logging of server messages.
+#
+# Logging recognizes 3 symbolic names of log devices:
+# stdout - Standard output
+# stderr - Standard error output
+# syslog - Syslog
+#
+# In addition, arbitrary number of log files may be specified (see below).
+#
+# Log messages are characterized by severity and category.
+# Supported severities:
+# debug - Debug messages. Must be turned on at compile time.
+# info - Informational messages.
+# notice - Notices and hints.
+# warning - Warnings. An action from the operator may be required.
+# error - Recoverable error. Some action should be taken.
+# fatal - Non-recoverable errors resulting in server shutdown.
+# (Not supported yet.)
+# all - All severities.
+#
+# Categories designate the source of the log message and roughly correspond
+# to server modules
+# Supported categories:
+# server - Messages related to general operation of the server.
+# zone - Messages related to zones, zone parsing and loading.
+# answering - Messages regarding query processing and response creation.
+# any - All categories
+#
+# More severities (separated by commas) may be listed for each category.
+# All applicable severities must be listed.
+# (I.e. specifying 'error' severity does mean: 'log error messages',
+# and NOT 'log all messages of severity error and above'.)
+#
+# Default settings (in case there are no entries in 'log' section or the section
+# is missing at all):
+#
+# stderr { any error; }
+# syslog { any error; }
+log {
+
+ # Log entry
+ #
+ # Format 1:
+ # <log> {
+ # <category1> <severity1> [, <severity2> ...];
+ # <category2> <severity1> [, <severity2> ...];
+ # ...
+ # }
+ syslog { # <log> is a symbolic name of a log device (see above)
+ # log errors of any category
+ any error; # for <category> and <severity> see above
+ # log also warnings and notices from category 'zone'
+ zone warning, notice;
+ # log info from server
+ server info;
+ }
+
+ # Log fatal, warnings and errors to stderr
+ stderr {
+ any error, warning;
+ }
+
+ # Format 2:
+ # file <path> {
+ # <category1> <severity1> [, <severity2> ...];
+ # <category2> <severity1> [, <severity2> ...];
+ # }
+ file "/tmp/knot-sample/knotd.debug" { # <path> is absolute or relative path to log file
+ server debug;
+ }
+}
diff --git a/samples/knot.min.conf b/samples/knot.min.conf
new file mode 100644
index 0000000..f9bc29c
--- /dev/null
+++ b/samples/knot.min.conf
@@ -0,0 +1,30 @@
+#
+# knot.min.conf
+#
+# This is a sample of a minimal configuration file for Knot DNS.
+#
+# For exhaustive list of all options see samples/knot.full.conf
+# in the source directory.
+#
+
+system {
+ identity "Knot DNS minimal configuration";
+ storage "/tmp/knot-minimal";
+}
+
+interfaces {
+ ipv4 { address 127.0.0.1@53533; }
+}
+
+zones {
+ example.com {
+ file "samples/example.com.zone";
+ }
+}
+
+log {
+ stdout { any info, notice; }
+ stderr { any debug, warning, error; }
+ syslog {}
+ file "/tmp/knot-minimal/knotd.log" { any all; }
+}
diff --git a/samples/knot.sample.conf.in b/samples/knot.sample.conf.in
new file mode 100644
index 0000000..7084595
--- /dev/null
+++ b/samples/knot.sample.conf.in
@@ -0,0 +1,18 @@
+system {
+ identity "@package@ @version@";
+ storage "@localstatedir@/@package@";
+}
+
+interfaces {
+ my-iface { address 127.0.0.1@5353; }
+}
+
+zones {
+ example.com {
+ file "@sysconfdir@/example.com.zone";
+ }
+}
+
+log {
+ syslog { any warning, error; }
+}
diff --git a/scripts/parse_dump.py b/scripts/parse_dump.py
new file mode 100755
index 0000000..d9cc44b
--- /dev/null
+++ b/scripts/parse_dump.py
@@ -0,0 +1,145 @@
+#!/usr/bin/python
+from scapy.all import *
+from binascii import *
+import base64
+import sys
+import dns.rdata
+import dns.rrset
+from struct import *
+
+fr = open(sys.argv[1] + ".raw_data", 'wb')
+fp = open(sys.argv[1] + ".parsed_data", 'wb')
+
+def chop_and_write_rr_query(rr):
+ name = dns.name.from_text(rr.qname)
+# print rr.qname
+
+ wire = name.to_wire()
+ fp.write(pack('B', len(wire)))
+# print len(wire)
+ fp.write(wire)
+ fp.write(pack('H', rr.qtype))
+ fp.write(pack('H', rr.qclass))
+
+def chop_and_write_rr_response(rr):
+ name = dns.name.from_text(rr.rrname)
+# print rr.rrname
+
+ wire = name.to_wire()
+ fp.write(pack('B', len(wire)))
+ fp.write(wire)
+ fp.write(pack('H', rr.type))
+ fp.write(pack('H', rr.rclass))
+ fp.write(pack('L', rr.ttl))
+
+ try:
+ rdata = dns.rdata.from_wire(rr.rclass, rr.type, rr.rdata, 0, len(rr.rdata))
+ fp.write(pack('H', len(rr.rdata)))
+# print "type ", rr.type, "length ", len(rr.rdata)
+# OPT has length 0 - it should have no rdata
+ rdata.to_wire(fp)
+ except:
+
+ try:
+# if rr.rdata[0] != '\#':
+ rdata = dns.rdata.from_text(rr.rclass, rr.type, rr.rdata)
+ try:
+ fp.write(pack('H', len(rdata)))
+ except:
+ # no length - no way to know wire length
+ try:
+# print "unknown length for type", rr.type
+# if rr.type == 2:
+# fp.seek(1, 1)
+# old = fp.tell()
+# rdata.to_wire(fp)
+# size = fp.tell() - old
+# fp.seek(-(size + 1), 1)
+# fp.write(pack('B', size))
+# fp.seek(0, 2)
+# else:
+ rdata.to_wire(fp)
+ except Exception as e:
+ print 'Error, exiting: ', e
+ sys.exit(-1)
+ except Exception as e:
+ print 'Error,', e
+ print 'could not parse rdata type: ', rr.type
+ print 'dumping directly (hopefully it is SOA)'
+# i need to do some kind of rollback here...
+ fp.write(pack('H', len(rr.rdata)))
+ fp.write(rr.rdata)
+
+
+ if rr.type == 50:
+ f = open('nsec3debug', 'wb')
+ rdata.to_wire(f)
+ f.close()
+
+def chop_and_write_section_response(section):
+ if section == None:
+ return
+ i = 0
+ rr = section.getlayer(i);
+ while rr != None:
+ chop_and_write_rr_response(rr)
+ i += 1
+ rr = section.getlayer(i)
+
+def chop_and_write_section_query(section):
+ if section == None:
+ return
+ i = 0
+ rr = section.getlayer(i);
+ while rr != None:
+ chop_and_write_rr_query(rr)
+ i += 1
+ rr = section.getlayer(i)
+
+def chop_and_write_packet(packet):
+ fp.write(pack('H', packet.id))
+# fp.write(pack('H', packet.qr))
+# fp.write(pack('H', packet.opcode))
+# fp.write(pack('H', packet.aa)) #TODO these are not uint16_t
+# fp.write(pack('H', packet.rcode))
+ fp.write(pack('H', packet.qdcount))
+ fp.write(pack('H', packet.ancount))
+ fp.write(pack('H', packet.nscount))
+ fp.write(pack('H', packet.arcount))
+
+#write query flag
+ fp.write(pack('H', packet.qr))
+
+ chop_and_write_section_query(packet.qd)
+ chop_and_write_section_response(packet.an)
+ chop_and_write_section_response(packet.ns)
+ chop_and_write_section_response(packet.ar)
+
+packets = rdpcap(sys.argv[1])
+
+total_length = len(packets)
+
+fr.write(pack('L', total_length))
+fp.write(pack('L', total_length))
+
+for packet in packets:
+ try:
+ data = a2b_hex(str(packet['DNS']).encode('hex'))
+ fr.write(pack('H', packet.qr))
+ fr.write(pack('H', len(data)))
+ fr.write(data)
+ chop_and_write_packet(packet['DNS'])
+ except IndexError:
+ print 'non-DNS packet'
+ total_length -= 1
+
+fr.seek(0)
+fp.seek(0)
+
+fr.write(pack('L', total_length))
+fp.write(pack('L', total_length))
+
+print 'written ', total_length, 'packets'
+
+fr.close()
+fp.close()
diff --git a/scripts/pcap2dnsp.py b/scripts/pcap2dnsp.py
new file mode 100755
index 0000000..305f8bb
--- /dev/null
+++ b/scripts/pcap2dnsp.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+from scapy.all import *
+import sys
+
+nstypes = { 0:"ANY", 255:"ALL",1:"A", 2:"NS", 3:"MD", 4:"MD", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG", 9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT", 17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME"}
+
+a=rdpcap(sys.argv[1]);
+
+f=open(sys.argv[2], 'w');
+
+for i in a:
+ try:
+ f.write(i[3].qname+' '+nstypes[i[3].qtype]+'\n')
+ except:
+ continue
+
+f.close()
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..3f65566
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,336 @@
+ACLOCAL_AMFLAGS = -I ../m4
+libexec_PROGRAMS = knot-zcompile unittests unittests-zcompile unittests-libknot-realdata unittests-libknot
+sbin_PROGRAMS = knotc knotd
+MANPAGES = knotc.8 knotd.8
+man8_MANS = knotc.8 knotd.8
+EXTRA_DIST = $(man8_MANS)
+
+# $(YACC) will generate header file
+AM_CFLAGS = -Wall -Ilibknot -DLIBEXECDIR='"$(libexecdir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DSBINDIR='"$(sbindir)"'
+AM_YFLAGS = -d
+libknotd_la_YFLAGS = -pcf_ -d
+libknotd_la_LFLAGS = # TODO: reentrant parser, prefix
+
+BUILT_SOURCES = \
+ tests/libknot/parsed_data.rc \
+ tests/libknot/realdata/parsed_data.rc \
+ tests/libknot/raw_data_queries.rc \
+ tests/libknot/raw_data.rc \
+ tests/libknot/realdata/raw_data.rc \
+ tests/libknot/parsed_data_queries.rc \
+ tests/sample_conf.rc \
+ zparser.h \
+ zparser.c \
+ zlexer.c \
+ libknotd_la-cf-lex.c \
+ libknotd_la-cf-parse.c \
+ libknotd_la-cf-parse.h
+
+CLEANFILES = \
+ tests/libknot/parsed_data.rc \
+ tests/libknot/realdata/parsed_data.rc \
+ tests/libknot/raw_data_queries.rc \
+ tests/libknot/raw_data.rc \
+ tests/libknot/realdata/raw_data.rc \
+ tests/libknot/parsed_data_queries.rc \
+ tests/sample_conf.rc \
+ zparser.h \
+ zparser.c \
+ zlexer.c \
+ libknotd_la-cf-lex.c \
+ libknotd_la-cf-parse.c \
+ libknotd_la-cf-parse.h
+
+knotc_SOURCES = \
+ knot/ctl/knotc_main.c
+
+knot_zcompile_SOURCES = \
+ zcompile/zcompile_main.c \
+ zcompile/zcompile-error.c \
+ zcompile/parser-util.h \
+ zcompile/parser-descriptor.h \
+ zcompile/zparser.y \
+ zcompile/zlexer.l \
+ zcompile/zcompile.c \
+ zcompile/parser-util.c \
+ zcompile/parser-descriptor.c
+
+unittests_SOURCES = \
+ tests/common/acl_tests.c \
+ tests/common/acl_tests.h \
+ tests/common/da_tests.c \
+ tests/common/da_tests.h \
+ tests/common/events_tests.c \
+ tests/common/events_tests.h \
+ tests/common/skiplist_tests.c \
+ tests/common/skiplist_tests.h \
+ tests/common/slab_tests.c \
+ tests/common/slab_tests.h \
+ tests/common/fdset_tests.c \
+ tests/common/fdset_tests.h \
+ tests/knot/conf_tests.c \
+ tests/knot/conf_tests.h \
+ tests/knot/dthreads_tests.c \
+ tests/knot/dthreads_tests.h \
+ tests/knot/journal_tests.c \
+ tests/knot/journal_tests.h \
+ tests/knot/server_tests.c \
+ tests/knot/server_tests.h \
+ tests/unittests_main.c
+
+unittests_libknot_realdata_SOURCES = \
+ tests/libknot/realdata/libknot/dname_tests_realdata.c \
+ tests/libknot/realdata/libknot/response_tests_realdata.c \
+ tests/libknot/realdata/libknot/edns_tests_realdata.c \
+ tests/libknot/realdata/libknot/node_tests_realdata.c \
+ tests/libknot/realdata/libknot/rdata_tests_realdata.c \
+ tests/libknot/realdata/libknot/rrset_tests_realdata.c \
+ tests/libknot/realdata/libknot/zone_tests_realdata.c \
+ tests/libknot/realdata/libknot/zonedb_tests_realdata.c \
+ tests/libknot/realdata/libknot/packet_tests_realdata.h \
+ tests/libknot/realdata/libknot/packet_tests_realdata.c \
+ tests/libknot/realdata/libknot_tests_loader_realdata.h \
+ tests/libknot/realdata/libknot_tests_loader_realdata.c \
+ tests/libknot/realdata/unittests_libknot_realdata.c
+
+unittests_libknot_SOURCES = \
+ tests/libknot/libknot/cuckoo_tests.c \
+ tests/libknot/libknot/cuckoo_tests.h \
+ tests/libknot/libknot/response_tests.h \
+ tests/libknot/libknot/response_tests.c \
+ tests/libknot/libknot/dname_tests.c \
+ tests/libknot/libknot/dname_tests.h \
+ tests/libknot/libknot/dname_table_tests.h \
+ tests/libknot/libknot/dname_table_tests.c \
+ tests/libknot/libknot/nsec3_tests.h \
+ tests/libknot/libknot/nsec3_tests.c \
+ tests/libknot/libknot/packet_tests.h \
+ tests/libknot/libknot/packet_tests.c \
+ tests/libknot/libknot/query_tests.h \
+ tests/libknot/libknot/query_tests.c \
+ tests/libknot/libknot/edns_tests.c \
+ tests/libknot/libknot/edns_tests.h \
+ tests/libknot/libknot/node_tests.c \
+ tests/libknot/libknot/node_tests.h \
+ tests/libknot/libknot/rdata_tests.c \
+ tests/libknot/libknot/rdata_tests.h \
+ tests/libknot/libknot/rrset_tests.c \
+ tests/libknot/libknot/rrset_tests.h \
+ tests/libknot/libknot/zone_tests.c \
+ tests/libknot/libknot/zone_tests.h \
+ tests/libknot/libknot/zone_tree_tests.h\
+ tests/libknot/libknot/zone_tree_tests.c \
+ tests/libknot/libknot/zonedb_tests.c \
+ tests/libknot/libknot/zonedb_tests.h \
+ tests/libknot/unittests_libknot.c
+
+unittests_zcompile_SOURCES = \
+ zcompile/parser-util.h \
+ zcompile/parser-descriptor.h \
+ zcompile/zcompile-error.c \
+ zcompile/zparser.y \
+ zcompile/zlexer.l \
+ zcompile/zcompile.c \
+ zcompile/parser-util.c \
+ zcompile/parser-descriptor.c \
+ zcompile/tests/unittests_zp_main.c
+
+nodist_unittests_SOURCES = \
+ tests/libknot/parsed_data.rc \
+ tests/libknot/raw_data_queries.rc \
+ tests/libknot/raw_data.rc \
+ tests/libknot/parsed_data_queries.rc \
+ tests/sample_conf.rc
+
+knotd_SOURCES = \
+ knot/main.c
+
+noinst_LTLIBRARIES = libknot.la libknotd.la libknots.la
+
+libknot_la_SOURCES = \
+ libknot/util/libknot_error.c \
+ libknot/util/utils.c \
+ libknot/util/debug.c \
+ libknot/util/debug.h \
+ libknot/util/utils.h \
+ libknot/util/descriptor.c \
+ libknot/util/tolower.h \
+ libknot/util/tolower.c \
+ libknot/util/descriptor.h \
+ libknot/util/wire.h \
+ libknot/packet/query.c \
+ libknot/packet/response.c \
+ libknot/packet/packet.c \
+ libknot/packet/packet.h \
+ libknot/packet/query.h \
+ libknot/packet/response.h \
+ libknot/zone/zone.c \
+ libknot/zone/zone-contents.c \
+ libknot/zone/zone-tree.c \
+ libknot/zone/zone-tree.h \
+ libknot/zone/node.h \
+ libknot/zone/zone.h \
+ libknot/zone/zone-contents.h \
+ libknot/zone/zonedb.c \
+ libknot/zone/zonedb.h \
+ libknot/zone/node.c \
+ libknot/zone/dname-table.h \
+ libknot/zone/dname-table.c \
+ libknot/hash/hash-functions.c \
+ libknot/hash/cuckoo-hash-table.c \
+ libknot/hash/universal-system.c \
+ libknot/hash/universal-system.h \
+ libknot/hash/cuckoo-hash-table.h \
+ libknot/hash/hash-functions.h \
+ libknot/nameserver/name-server.h \
+ libknot/nameserver/name-server.c \
+ libknot/updates/changesets.h \
+ libknot/updates/changesets.c \
+ libknot/updates/xfr-in.h \
+ libknot/updates/xfr-in.c \
+ libknot/updates/ddns.h \
+ libknot/updates/ddns.c \
+ libknot/edns.c \
+ libknot/rrset.c \
+ libknot/dname.c \
+ libknot/rdata.c \
+ libknot/nsec3.c \
+ libknot/consts.h \
+ libknot/edns.h \
+ libknot/rdata.h \
+ libknot/libknot.h \
+ libknot/dname.h \
+ libknot/rrset.h \
+ libknot/nsec3.h \
+ libknot/tsig.h \
+ libknot/tsig.c \
+ libknot/tsig-op.h \
+ libknot/tsig-op.c
+
+libknots_la_SOURCES = \
+ common/slab/slab.c \
+ common/slab/malloc.c \
+ common/slab/slab.h \
+ common/slab/malloc.h \
+ common/libtap/tap.c \
+ common/libtap/tap.h \
+ common/libtap/tap_unit.h \
+ common/lists.c \
+ common/base32.c \
+ common/lists.h \
+ common/base32.h \
+ common/print.c \
+ common/print.h \
+ common/dynamic-array.c \
+ common/skip-list.c \
+ common/base32hex.c \
+ common/skip-list.h \
+ common/general-tree.h \
+ common/general-tree.c \
+ common/dynamic-array.h \
+ common/tree.h \
+ common/base32hex.h \
+ common/evqueue.h \
+ common/evqueue.c \
+ common/evsched.h \
+ common/evsched.c \
+ common/acl.h \
+ common/acl.c \
+ common/sockaddr.h \
+ common/sockaddr.c \
+ common/crc.h \
+ common/crc.c \
+ common/ref.h \
+ common/ref.c \
+ common/errors.h \
+ common/errors.c \
+ common/WELL1024a.h \
+ common/WELL1024a.c \
+ common/fdset.h \
+ common/fdset.c \
+ common/fdset_poll.h \
+ common/fdset_poll.c \
+ common/fdset_kqueue.h \
+ common/fdset_kqueue.c \
+ common/fdset_epoll.h \
+ common/fdset_epoll.c
+
+libknotd_la_SOURCES = \
+ knot/stat/gatherer.c \
+ knot/stat/stat.c \
+ knot/stat/gatherer.h \
+ knot/stat/stat.h \
+ knot/common.h \
+ knot/other/log.c \
+ knot/other/log.h \
+ knot/other/debug.h \
+ knot/other/error.h \
+ knot/other/error.c \
+ knot/conf/cf-parse.y \
+ knot/conf/cf-lex.l \
+ knot/conf/conf.c \
+ knot/conf/logconf.c \
+ knot/conf/logconf.h \
+ knot/conf/conf.h \
+ knot/ctl/process.c \
+ knot/ctl/process.h \
+ knot/server/dthreads.c \
+ knot/server/journal.c \
+ knot/server/socket.c \
+ knot/server/server.c \
+ knot/server/udp-handler.c \
+ knot/server/tcp-handler.c \
+ knot/server/xfr-handler.c \
+ knot/server/zones.c \
+ knot/server/socket.h \
+ knot/server/udp-handler.h \
+ knot/server/tcp-handler.h \
+ knot/server/xfr-handler.h \
+ knot/server/dthreads.h \
+ knot/server/journal.h \
+ knot/server/zones.h \
+ knot/server/notify.h \
+ knot/server/notify.c \
+ knot/server/zones.h \
+ knot/zone/zone-load.c \
+ knot/zone/zone-load.h \
+ knot/zone/zone-dump.c \
+ knot/zone/zone-dump-text.c \
+ knot/zone/zone-dump-text.h \
+ knot/zone/zone-dump.h \
+ knot/server/server.h
+
+libknotd_la_LIBADD = ../libknot/libknot.la libknots.la @LIBOBJS@
+libknots_la_LIBADD = @LIBOBJS@
+knotd_LDADD = libknotd.la ../libknot/libknot.la libknots.la @LIBOBJS@
+knotc_LDADD = libknotd.la ../libknot/libknot.la libknots.la @LIBOBJS@
+knot_zcompile_LDADD = libknots.la ../libknot/libknot.la libknotd.la @LIBOBJS@
+unittests_LDADD = libknotd.la libknots.la @LIBOBJS@
+unittests_zcompile_LDADD = ../libknot/libknot.la libknots.la libknotd.la @LIBOBJS@
+unittests_libknot_LDADD = ../libknot/libknot.la libknots.la @LIBOBJS@
+unittests_libknot_realdata_LDADD = ../libknot/libknot.la libknots.la @LIBOBJS@
+
+# automake complains on % rules:
+# `%'-style pattern rules are a GNU make extension
+
+tests/libknot/parsed_data.rc: tests/libknot/files/parsed_data
+ ../resource.sh tests/libknot/files/parsed_data >$@
+
+tests/libknot/realdata/parsed_data.rc: tests/libknot/realdata/files/parsed_data
+ ../resource.sh tests/libknot/realdata/files/parsed_data >$@
+
+tests/libknot/parsed_data_queries.rc: tests/libknot/files/parsed_data_queries
+ ../resource.sh tests/libknot/files/parsed_data_queries >$@
+
+tests/libknot/raw_data_queries.rc: tests/libknot/files/raw_data_queries
+ ../resource.sh tests/libknot/files/raw_data_queries >$@
+
+tests/libknot/raw_data.rc: tests/libknot/files/raw_data
+ ../resource.sh tests/libknot/files/raw_data >$@
+
+tests/libknot/realdata/raw_data.rc: tests/libknot/realdata/files/raw_data
+ ../resource.sh tests/libknot/realdata/files/raw_data >$@
+
+tests/sample_conf.rc: tests/files/sample_conf
+ ../resource.sh tests/files/sample_conf >$@
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..7811da5
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,2396 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+libexec_PROGRAMS = knot-zcompile$(EXEEXT) unittests$(EXEEXT) \
+ unittests-zcompile$(EXEEXT) \
+ unittests-libknot-realdata$(EXEEXT) unittests-libknot$(EXEEXT)
+sbin_PROGRAMS = knotc$(EXEEXT) knotd$(EXEEXT)
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/config.h.in libknotd_la-cf-lex.c \
+ libknotd_la-cf-parse.c libknotd_la-cf-parse.h zlexer.c \
+ zparser.c zparser.h
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compiler_flags.m4 \
+ $(top_srcdir)/m4/ax_ext.m4 \
+ $(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libknot_la_LIBADD =
+am_libknot_la_OBJECTS = libknot_error.lo utils.lo debug.lo \
+ descriptor.lo tolower.lo query.lo response.lo packet.lo \
+ zone.lo zone-contents.lo zone-tree.lo zonedb.lo node.lo \
+ dname-table.lo hash-functions.lo cuckoo-hash-table.lo \
+ universal-system.lo name-server.lo changesets.lo xfr-in.lo \
+ ddns.lo edns.lo rrset.lo dname.lo rdata.lo nsec3.lo tsig.lo \
+ tsig-op.lo
+libknot_la_OBJECTS = $(am_libknot_la_OBJECTS)
+libknotd_la_DEPENDENCIES = ../libknot/libknot.la libknots.la @LIBOBJS@
+am_libknotd_la_OBJECTS = gatherer.lo stat.lo log.lo error.lo \
+ libknotd_la-cf-parse.lo libknotd_la-cf-lex.lo conf.lo \
+ logconf.lo process.lo dthreads.lo journal.lo socket.lo \
+ server.lo udp-handler.lo tcp-handler.lo xfr-handler.lo \
+ zones.lo notify.lo zone-load.lo zone-dump.lo zone-dump-text.lo
+libknotd_la_OBJECTS = $(am_libknotd_la_OBJECTS)
+libknots_la_DEPENDENCIES = @LIBOBJS@
+am_libknots_la_OBJECTS = slab.lo malloc.lo tap.lo lists.lo base32.lo \
+ print.lo dynamic-array.lo skip-list.lo base32hex.lo \
+ general-tree.lo evqueue.lo evsched.lo acl.lo sockaddr.lo \
+ crc.lo ref.lo errors.lo WELL1024a.lo fdset.lo fdset_poll.lo \
+ fdset_kqueue.lo fdset_epoll.lo
+libknots_la_OBJECTS = $(am_libknots_la_OBJECTS)
+am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \
+ "$(DESTDIR)$(man8dir)"
+PROGRAMS = $(libexec_PROGRAMS) $(sbin_PROGRAMS)
+am_knot_zcompile_OBJECTS = zcompile_main.$(OBJEXT) \
+ zcompile-error.$(OBJEXT) zparser.$(OBJEXT) zlexer.$(OBJEXT) \
+ zcompile.$(OBJEXT) parser-util.$(OBJEXT) \
+ parser-descriptor.$(OBJEXT)
+knot_zcompile_OBJECTS = $(am_knot_zcompile_OBJECTS)
+knot_zcompile_DEPENDENCIES = libknots.la ../libknot/libknot.la \
+ libknotd.la @LIBOBJS@
+am_knotc_OBJECTS = knotc_main.$(OBJEXT)
+knotc_OBJECTS = $(am_knotc_OBJECTS)
+knotc_DEPENDENCIES = libknotd.la ../libknot/libknot.la libknots.la \
+ @LIBOBJS@ $(am__empty)
+am_knotd_OBJECTS = main.$(OBJEXT)
+knotd_OBJECTS = $(am_knotd_OBJECTS)
+knotd_DEPENDENCIES = libknotd.la ../libknot/libknot.la libknots.la \
+ @LIBOBJS@ $(am__empty)
+am_unittests_OBJECTS = acl_tests.$(OBJEXT) da_tests.$(OBJEXT) \
+ events_tests.$(OBJEXT) skiplist_tests.$(OBJEXT) \
+ slab_tests.$(OBJEXT) fdset_tests.$(OBJEXT) \
+ conf_tests.$(OBJEXT) dthreads_tests.$(OBJEXT) \
+ journal_tests.$(OBJEXT) server_tests.$(OBJEXT) \
+ unittests_main.$(OBJEXT)
+nodist_unittests_OBJECTS =
+unittests_OBJECTS = $(am_unittests_OBJECTS) \
+ $(nodist_unittests_OBJECTS)
+unittests_DEPENDENCIES = libknotd.la libknots.la @LIBOBJS@
+am_unittests_libknot_OBJECTS = cuckoo_tests.$(OBJEXT) \
+ response_tests.$(OBJEXT) dname_tests.$(OBJEXT) \
+ dname_table_tests.$(OBJEXT) nsec3_tests.$(OBJEXT) \
+ packet_tests.$(OBJEXT) query_tests.$(OBJEXT) \
+ edns_tests.$(OBJEXT) node_tests.$(OBJEXT) \
+ rdata_tests.$(OBJEXT) rrset_tests.$(OBJEXT) \
+ zone_tests.$(OBJEXT) zone_tree_tests.$(OBJEXT) \
+ zonedb_tests.$(OBJEXT) unittests_libknot.$(OBJEXT)
+unittests_libknot_OBJECTS = $(am_unittests_libknot_OBJECTS)
+unittests_libknot_DEPENDENCIES = ../libknot/libknot.la libknots.la \
+ @LIBOBJS@ $(am__empty)
+am_unittests_libknot_realdata_OBJECTS = \
+ dname_tests_realdata.$(OBJEXT) \
+ response_tests_realdata.$(OBJEXT) \
+ edns_tests_realdata.$(OBJEXT) node_tests_realdata.$(OBJEXT) \
+ rdata_tests_realdata.$(OBJEXT) rrset_tests_realdata.$(OBJEXT) \
+ zone_tests_realdata.$(OBJEXT) zonedb_tests_realdata.$(OBJEXT) \
+ packet_tests_realdata.$(OBJEXT) \
+ libknot_tests_loader_realdata.$(OBJEXT) \
+ unittests_libknot_realdata.$(OBJEXT)
+unittests_libknot_realdata_OBJECTS = \
+ $(am_unittests_libknot_realdata_OBJECTS)
+unittests_libknot_realdata_DEPENDENCIES = ../libknot/libknot.la \
+ libknots.la @LIBOBJS@
+am_unittests_zcompile_OBJECTS = zcompile-error.$(OBJEXT) \
+ zparser.$(OBJEXT) zlexer.$(OBJEXT) zcompile.$(OBJEXT) \
+ parser-util.$(OBJEXT) parser-descriptor.$(OBJEXT) \
+ unittests_zp_main.$(OBJEXT)
+unittests_zcompile_OBJECTS = $(am_unittests_zcompile_OBJECTS)
+unittests_zcompile_DEPENDENCIES = ../libknot/libknot.la libknots.la \
+ libknotd.la @LIBOBJS@
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
+LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(LEX) $(LFLAGS) $(AM_LFLAGS)
+YLWRAP = $(top_srcdir)/ylwrap
+@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
+YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(YACC) $(YFLAGS) $(AM_YFLAGS)
+SOURCES = $(libknot_la_SOURCES) $(libknotd_la_SOURCES) \
+ $(libknots_la_SOURCES) $(knot_zcompile_SOURCES) \
+ $(knotc_SOURCES) $(knotd_SOURCES) $(unittests_SOURCES) \
+ $(nodist_unittests_SOURCES) $(unittests_libknot_SOURCES) \
+ $(unittests_libknot_realdata_SOURCES) \
+ $(unittests_zcompile_SOURCES)
+DIST_SOURCES = $(libknot_la_SOURCES) $(libknotd_la_SOURCES) \
+ $(libknots_la_SOURCES) $(knot_zcompile_SOURCES) \
+ $(knotc_SOURCES) $(knotd_SOURCES) $(unittests_SOURCES) \
+ $(unittests_libknot_SOURCES) \
+ $(unittests_libknot_realdata_SOURCES) \
+ $(unittests_zcompile_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(man8_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIMD_FLAGS = @SIMD_FLAGS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I ../m4
+MANPAGES = knotc.8 knotd.8
+man8_MANS = knotc.8 knotd.8
+EXTRA_DIST = $(man8_MANS)
+
+# $(YACC) will generate header file
+AM_CFLAGS = -Wall -Ilibknot -DLIBEXECDIR='"$(libexecdir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DSBINDIR='"$(sbindir)"'
+AM_YFLAGS = -d
+libknotd_la_YFLAGS = -pcf_ -d
+libknotd_la_LFLAGS = # TODO: reentrant parser, prefix
+BUILT_SOURCES = \
+ tests/libknot/parsed_data.rc \
+ tests/libknot/realdata/parsed_data.rc \
+ tests/libknot/raw_data_queries.rc \
+ tests/libknot/raw_data.rc \
+ tests/libknot/realdata/raw_data.rc \
+ tests/libknot/parsed_data_queries.rc \
+ tests/sample_conf.rc \
+ zparser.h \
+ zparser.c \
+ zlexer.c \
+ libknotd_la-cf-lex.c \
+ libknotd_la-cf-parse.c \
+ libknotd_la-cf-parse.h
+
+CLEANFILES = \
+ tests/libknot/parsed_data.rc \
+ tests/libknot/realdata/parsed_data.rc \
+ tests/libknot/raw_data_queries.rc \
+ tests/libknot/raw_data.rc \
+ tests/libknot/realdata/raw_data.rc \
+ tests/libknot/parsed_data_queries.rc \
+ tests/sample_conf.rc \
+ zparser.h \
+ zparser.c \
+ zlexer.c \
+ libknotd_la-cf-lex.c \
+ libknotd_la-cf-parse.c \
+ libknotd_la-cf-parse.h
+
+knotc_SOURCES = \
+ knot/ctl/knotc_main.c
+
+knot_zcompile_SOURCES = \
+ zcompile/zcompile_main.c \
+ zcompile/zcompile-error.c \
+ zcompile/parser-util.h \
+ zcompile/parser-descriptor.h \
+ zcompile/zparser.y \
+ zcompile/zlexer.l \
+ zcompile/zcompile.c \
+ zcompile/parser-util.c \
+ zcompile/parser-descriptor.c
+
+unittests_SOURCES = \
+ tests/common/acl_tests.c \
+ tests/common/acl_tests.h \
+ tests/common/da_tests.c \
+ tests/common/da_tests.h \
+ tests/common/events_tests.c \
+ tests/common/events_tests.h \
+ tests/common/skiplist_tests.c \
+ tests/common/skiplist_tests.h \
+ tests/common/slab_tests.c \
+ tests/common/slab_tests.h \
+ tests/common/fdset_tests.c \
+ tests/common/fdset_tests.h \
+ tests/knot/conf_tests.c \
+ tests/knot/conf_tests.h \
+ tests/knot/dthreads_tests.c \
+ tests/knot/dthreads_tests.h \
+ tests/knot/journal_tests.c \
+ tests/knot/journal_tests.h \
+ tests/knot/server_tests.c \
+ tests/knot/server_tests.h \
+ tests/unittests_main.c
+
+unittests_libknot_realdata_SOURCES = \
+ tests/libknot/realdata/libknot/dname_tests_realdata.c \
+ tests/libknot/realdata/libknot/response_tests_realdata.c \
+ tests/libknot/realdata/libknot/edns_tests_realdata.c \
+ tests/libknot/realdata/libknot/node_tests_realdata.c \
+ tests/libknot/realdata/libknot/rdata_tests_realdata.c \
+ tests/libknot/realdata/libknot/rrset_tests_realdata.c \
+ tests/libknot/realdata/libknot/zone_tests_realdata.c \
+ tests/libknot/realdata/libknot/zonedb_tests_realdata.c \
+ tests/libknot/realdata/libknot/packet_tests_realdata.h \
+ tests/libknot/realdata/libknot/packet_tests_realdata.c \
+ tests/libknot/realdata/libknot_tests_loader_realdata.h \
+ tests/libknot/realdata/libknot_tests_loader_realdata.c \
+ tests/libknot/realdata/unittests_libknot_realdata.c
+
+unittests_libknot_SOURCES = \
+ tests/libknot/libknot/cuckoo_tests.c \
+ tests/libknot/libknot/cuckoo_tests.h \
+ tests/libknot/libknot/response_tests.h \
+ tests/libknot/libknot/response_tests.c \
+ tests/libknot/libknot/dname_tests.c \
+ tests/libknot/libknot/dname_tests.h \
+ tests/libknot/libknot/dname_table_tests.h \
+ tests/libknot/libknot/dname_table_tests.c \
+ tests/libknot/libknot/nsec3_tests.h \
+ tests/libknot/libknot/nsec3_tests.c \
+ tests/libknot/libknot/packet_tests.h \
+ tests/libknot/libknot/packet_tests.c \
+ tests/libknot/libknot/query_tests.h \
+ tests/libknot/libknot/query_tests.c \
+ tests/libknot/libknot/edns_tests.c \
+ tests/libknot/libknot/edns_tests.h \
+ tests/libknot/libknot/node_tests.c \
+ tests/libknot/libknot/node_tests.h \
+ tests/libknot/libknot/rdata_tests.c \
+ tests/libknot/libknot/rdata_tests.h \
+ tests/libknot/libknot/rrset_tests.c \
+ tests/libknot/libknot/rrset_tests.h \
+ tests/libknot/libknot/zone_tests.c \
+ tests/libknot/libknot/zone_tests.h \
+ tests/libknot/libknot/zone_tree_tests.h\
+ tests/libknot/libknot/zone_tree_tests.c \
+ tests/libknot/libknot/zonedb_tests.c \
+ tests/libknot/libknot/zonedb_tests.h \
+ tests/libknot/unittests_libknot.c
+
+unittests_zcompile_SOURCES = \
+ zcompile/parser-util.h \
+ zcompile/parser-descriptor.h \
+ zcompile/zcompile-error.c \
+ zcompile/zparser.y \
+ zcompile/zlexer.l \
+ zcompile/zcompile.c \
+ zcompile/parser-util.c \
+ zcompile/parser-descriptor.c \
+ zcompile/tests/unittests_zp_main.c
+
+nodist_unittests_SOURCES = \
+ tests/libknot/parsed_data.rc \
+ tests/libknot/raw_data_queries.rc \
+ tests/libknot/raw_data.rc \
+ tests/libknot/parsed_data_queries.rc \
+ tests/sample_conf.rc
+
+knotd_SOURCES = \
+ knot/main.c
+
+noinst_LTLIBRARIES = libknot.la libknotd.la libknots.la
+libknot_la_SOURCES = \
+ libknot/util/libknot_error.c \
+ libknot/util/utils.c \
+ libknot/util/debug.c \
+ libknot/util/debug.h \
+ libknot/util/utils.h \
+ libknot/util/descriptor.c \
+ libknot/util/tolower.h \
+ libknot/util/tolower.c \
+ libknot/util/descriptor.h \
+ libknot/util/wire.h \
+ libknot/packet/query.c \
+ libknot/packet/response.c \
+ libknot/packet/packet.c \
+ libknot/packet/packet.h \
+ libknot/packet/query.h \
+ libknot/packet/response.h \
+ libknot/zone/zone.c \
+ libknot/zone/zone-contents.c \
+ libknot/zone/zone-tree.c \
+ libknot/zone/zone-tree.h \
+ libknot/zone/node.h \
+ libknot/zone/zone.h \
+ libknot/zone/zone-contents.h \
+ libknot/zone/zonedb.c \
+ libknot/zone/zonedb.h \
+ libknot/zone/node.c \
+ libknot/zone/dname-table.h \
+ libknot/zone/dname-table.c \
+ libknot/hash/hash-functions.c \
+ libknot/hash/cuckoo-hash-table.c \
+ libknot/hash/universal-system.c \
+ libknot/hash/universal-system.h \
+ libknot/hash/cuckoo-hash-table.h \
+ libknot/hash/hash-functions.h \
+ libknot/nameserver/name-server.h \
+ libknot/nameserver/name-server.c \
+ libknot/updates/changesets.h \
+ libknot/updates/changesets.c \
+ libknot/updates/xfr-in.h \
+ libknot/updates/xfr-in.c \
+ libknot/updates/ddns.h \
+ libknot/updates/ddns.c \
+ libknot/edns.c \
+ libknot/rrset.c \
+ libknot/dname.c \
+ libknot/rdata.c \
+ libknot/nsec3.c \
+ libknot/consts.h \
+ libknot/edns.h \
+ libknot/rdata.h \
+ libknot/libknot.h \
+ libknot/dname.h \
+ libknot/rrset.h \
+ libknot/nsec3.h \
+ libknot/tsig.h \
+ libknot/tsig.c \
+ libknot/tsig-op.h \
+ libknot/tsig-op.c
+
+libknots_la_SOURCES = \
+ common/slab/slab.c \
+ common/slab/malloc.c \
+ common/slab/slab.h \
+ common/slab/malloc.h \
+ common/libtap/tap.c \
+ common/libtap/tap.h \
+ common/libtap/tap_unit.h \
+ common/lists.c \
+ common/base32.c \
+ common/lists.h \
+ common/base32.h \
+ common/print.c \
+ common/print.h \
+ common/dynamic-array.c \
+ common/skip-list.c \
+ common/base32hex.c \
+ common/skip-list.h \
+ common/general-tree.h \
+ common/general-tree.c \
+ common/dynamic-array.h \
+ common/tree.h \
+ common/base32hex.h \
+ common/evqueue.h \
+ common/evqueue.c \
+ common/evsched.h \
+ common/evsched.c \
+ common/acl.h \
+ common/acl.c \
+ common/sockaddr.h \
+ common/sockaddr.c \
+ common/crc.h \
+ common/crc.c \
+ common/ref.h \
+ common/ref.c \
+ common/errors.h \
+ common/errors.c \
+ common/WELL1024a.h \
+ common/WELL1024a.c \
+ common/fdset.h \
+ common/fdset.c \
+ common/fdset_poll.h \
+ common/fdset_poll.c \
+ common/fdset_kqueue.h \
+ common/fdset_kqueue.c \
+ common/fdset_epoll.h \
+ common/fdset_epoll.c
+
+libknotd_la_SOURCES = \
+ knot/stat/gatherer.c \
+ knot/stat/stat.c \
+ knot/stat/gatherer.h \
+ knot/stat/stat.h \
+ knot/common.h \
+ knot/other/log.c \
+ knot/other/log.h \
+ knot/other/debug.h \
+ knot/other/error.h \
+ knot/other/error.c \
+ knot/conf/cf-parse.y \
+ knot/conf/cf-lex.l \
+ knot/conf/conf.c \
+ knot/conf/logconf.c \
+ knot/conf/logconf.h \
+ knot/conf/conf.h \
+ knot/ctl/process.c \
+ knot/ctl/process.h \
+ knot/server/dthreads.c \
+ knot/server/journal.c \
+ knot/server/socket.c \
+ knot/server/server.c \
+ knot/server/udp-handler.c \
+ knot/server/tcp-handler.c \
+ knot/server/xfr-handler.c \
+ knot/server/zones.c \
+ knot/server/socket.h \
+ knot/server/udp-handler.h \
+ knot/server/tcp-handler.h \
+ knot/server/xfr-handler.h \
+ knot/server/dthreads.h \
+ knot/server/journal.h \
+ knot/server/zones.h \
+ knot/server/notify.h \
+ knot/server/notify.c \
+ knot/server/zones.h \
+ knot/zone/zone-load.c \
+ knot/zone/zone-load.h \
+ knot/zone/zone-dump.c \
+ knot/zone/zone-dump-text.c \
+ knot/zone/zone-dump-text.h \
+ knot/zone/zone-dump.h \
+ knot/server/server.h
+
+libknotd_la_LIBADD = ../libknot/libknot.la libknots.la @LIBOBJS@
+libknots_la_LIBADD = @LIBOBJS@
+knotd_LDADD = libknotd.la ../libknot/libknot.la libknots.la @LIBOBJS@
+knotc_LDADD = libknotd.la ../libknot/libknot.la libknots.la @LIBOBJS@
+knot_zcompile_LDADD = libknots.la ../libknot/libknot.la libknotd.la @LIBOBJS@
+unittests_LDADD = libknotd.la libknots.la @LIBOBJS@
+unittests_zcompile_LDADD = ../libknot/libknot.la libknots.la libknotd.la @LIBOBJS@
+unittests_libknot_LDADD = ../libknot/libknot.la libknots.la @LIBOBJS@
+unittests_libknot_realdata_LDADD = ../libknot/libknot.la libknots.la @LIBOBJS@
+all: $(BUILT_SOURCES) config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status src/config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libknot.la: $(libknot_la_OBJECTS) $(libknot_la_DEPENDENCIES)
+ $(LINK) $(libknot_la_OBJECTS) $(libknot_la_LIBADD) $(LIBS)
+libknotd_la-cf-parse.h: libknotd_la-cf-parse.c
+ @if test ! -f $@; then \
+ rm -f libknotd_la-cf-parse.c; \
+ $(MAKE) $(AM_MAKEFLAGS) libknotd_la-cf-parse.c; \
+ else :; fi
+libknotd.la: $(libknotd_la_OBJECTS) $(libknotd_la_DEPENDENCIES)
+ $(LINK) $(libknotd_la_OBJECTS) $(libknotd_la_LIBADD) $(LIBS)
+libknots.la: $(libknots_la_OBJECTS) $(libknots_la_DEPENDENCIES)
+ $(LINK) $(libknots_la_OBJECTS) $(libknots_la_LIBADD) $(LIBS)
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)"
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
+
+clean-libexecPROGRAMS:
+ @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+zparser.h: zparser.c
+ @if test ! -f $@; then \
+ rm -f zparser.c; \
+ $(MAKE) $(AM_MAKEFLAGS) zparser.c; \
+ else :; fi
+knot-zcompile$(EXEEXT): $(knot_zcompile_OBJECTS) $(knot_zcompile_DEPENDENCIES)
+ @rm -f knot-zcompile$(EXEEXT)
+ $(LINK) $(knot_zcompile_OBJECTS) $(knot_zcompile_LDADD) $(LIBS)
+knotc$(EXEEXT): $(knotc_OBJECTS) $(knotc_DEPENDENCIES)
+ @rm -f knotc$(EXEEXT)
+ $(LINK) $(knotc_OBJECTS) $(knotc_LDADD) $(LIBS)
+knotd$(EXEEXT): $(knotd_OBJECTS) $(knotd_DEPENDENCIES)
+ @rm -f knotd$(EXEEXT)
+ $(LINK) $(knotd_OBJECTS) $(knotd_LDADD) $(LIBS)
+unittests$(EXEEXT): $(unittests_OBJECTS) $(unittests_DEPENDENCIES)
+ @rm -f unittests$(EXEEXT)
+ $(LINK) $(unittests_OBJECTS) $(unittests_LDADD) $(LIBS)
+unittests-libknot$(EXEEXT): $(unittests_libknot_OBJECTS) $(unittests_libknot_DEPENDENCIES)
+ @rm -f unittests-libknot$(EXEEXT)
+ $(LINK) $(unittests_libknot_OBJECTS) $(unittests_libknot_LDADD) $(LIBS)
+unittests-libknot-realdata$(EXEEXT): $(unittests_libknot_realdata_OBJECTS) $(unittests_libknot_realdata_DEPENDENCIES)
+ @rm -f unittests-libknot-realdata$(EXEEXT)
+ $(LINK) $(unittests_libknot_realdata_OBJECTS) $(unittests_libknot_realdata_LDADD) $(LIBS)
+unittests-zcompile$(EXEEXT): $(unittests_zcompile_OBJECTS) $(unittests_zcompile_DEPENDENCIES)
+ @rm -f unittests-zcompile$(EXEEXT)
+ $(LINK) $(unittests_zcompile_OBJECTS) $(unittests_zcompile_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WELL1024a.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acl_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32hex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/changesets.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuckoo-hash-table.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuckoo_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/da_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ddns.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname-table.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname_table_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dthreads.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dthreads_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynamic-array.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/events_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evqueue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evsched.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset_epoll.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset_kqueue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset_poll.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdset_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gatherer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/general-tree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-functions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/journal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/journal_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/knotc_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libknot_error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libknot_tests_loader_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libknotd_la-cf-lex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libknotd_la-cf-parse.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lists.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logconf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/name-server.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser-descriptor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser-util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdata_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdata_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ref.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrset_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrset_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/skip-list.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/skiplist_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slab_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockaddr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcp-handler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tolower.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig-op.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/udp-handler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unittests_libknot.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unittests_libknot_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unittests_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unittests_zp_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/universal-system.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfr-handler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfr-in.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zcompile-error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zcompile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zcompile_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zlexer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-contents.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-dump-text.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-dump.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-load.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-tree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone_tree_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zonedb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zonedb_tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zonedb_tests_realdata.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zones.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zparser.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libknot_error.lo: libknot/util/libknot_error.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot_error.lo -MD -MP -MF $(DEPDIR)/libknot_error.Tpo -c -o libknot_error.lo `test -f 'libknot/util/libknot_error.c' || echo '$(srcdir)/'`libknot/util/libknot_error.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libknot_error.Tpo $(DEPDIR)/libknot_error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/libknot_error.c' object='libknot_error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot_error.lo `test -f 'libknot/util/libknot_error.c' || echo '$(srcdir)/'`libknot/util/libknot_error.c
+
+utils.lo: libknot/util/utils.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utils.lo -MD -MP -MF $(DEPDIR)/utils.Tpo -c -o utils.lo `test -f 'libknot/util/utils.c' || echo '$(srcdir)/'`libknot/util/utils.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/utils.Tpo $(DEPDIR)/utils.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/utils.c' object='utils.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utils.lo `test -f 'libknot/util/utils.c' || echo '$(srcdir)/'`libknot/util/utils.c
+
+debug.lo: libknot/util/debug.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT debug.lo -MD -MP -MF $(DEPDIR)/debug.Tpo -c -o debug.lo `test -f 'libknot/util/debug.c' || echo '$(srcdir)/'`libknot/util/debug.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/debug.Tpo $(DEPDIR)/debug.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/debug.c' object='debug.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o debug.lo `test -f 'libknot/util/debug.c' || echo '$(srcdir)/'`libknot/util/debug.c
+
+descriptor.lo: libknot/util/descriptor.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT descriptor.lo -MD -MP -MF $(DEPDIR)/descriptor.Tpo -c -o descriptor.lo `test -f 'libknot/util/descriptor.c' || echo '$(srcdir)/'`libknot/util/descriptor.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/descriptor.Tpo $(DEPDIR)/descriptor.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/descriptor.c' object='descriptor.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o descriptor.lo `test -f 'libknot/util/descriptor.c' || echo '$(srcdir)/'`libknot/util/descriptor.c
+
+tolower.lo: libknot/util/tolower.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tolower.lo -MD -MP -MF $(DEPDIR)/tolower.Tpo -c -o tolower.lo `test -f 'libknot/util/tolower.c' || echo '$(srcdir)/'`libknot/util/tolower.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tolower.Tpo $(DEPDIR)/tolower.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/tolower.c' object='tolower.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tolower.lo `test -f 'libknot/util/tolower.c' || echo '$(srcdir)/'`libknot/util/tolower.c
+
+query.lo: libknot/packet/query.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT query.lo -MD -MP -MF $(DEPDIR)/query.Tpo -c -o query.lo `test -f 'libknot/packet/query.c' || echo '$(srcdir)/'`libknot/packet/query.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/query.Tpo $(DEPDIR)/query.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/packet/query.c' object='query.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o query.lo `test -f 'libknot/packet/query.c' || echo '$(srcdir)/'`libknot/packet/query.c
+
+response.lo: libknot/packet/response.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response.lo -MD -MP -MF $(DEPDIR)/response.Tpo -c -o response.lo `test -f 'libknot/packet/response.c' || echo '$(srcdir)/'`libknot/packet/response.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response.Tpo $(DEPDIR)/response.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/packet/response.c' object='response.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response.lo `test -f 'libknot/packet/response.c' || echo '$(srcdir)/'`libknot/packet/response.c
+
+packet.lo: libknot/packet/packet.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet.lo -MD -MP -MF $(DEPDIR)/packet.Tpo -c -o packet.lo `test -f 'libknot/packet/packet.c' || echo '$(srcdir)/'`libknot/packet/packet.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet.Tpo $(DEPDIR)/packet.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/packet/packet.c' object='packet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet.lo `test -f 'libknot/packet/packet.c' || echo '$(srcdir)/'`libknot/packet/packet.c
+
+zone.lo: libknot/zone/zone.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone.lo -MD -MP -MF $(DEPDIR)/zone.Tpo -c -o zone.lo `test -f 'libknot/zone/zone.c' || echo '$(srcdir)/'`libknot/zone/zone.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone.Tpo $(DEPDIR)/zone.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zone.c' object='zone.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone.lo `test -f 'libknot/zone/zone.c' || echo '$(srcdir)/'`libknot/zone/zone.c
+
+zone-contents.lo: libknot/zone/zone-contents.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-contents.lo -MD -MP -MF $(DEPDIR)/zone-contents.Tpo -c -o zone-contents.lo `test -f 'libknot/zone/zone-contents.c' || echo '$(srcdir)/'`libknot/zone/zone-contents.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-contents.Tpo $(DEPDIR)/zone-contents.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zone-contents.c' object='zone-contents.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-contents.lo `test -f 'libknot/zone/zone-contents.c' || echo '$(srcdir)/'`libknot/zone/zone-contents.c
+
+zone-tree.lo: libknot/zone/zone-tree.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-tree.lo -MD -MP -MF $(DEPDIR)/zone-tree.Tpo -c -o zone-tree.lo `test -f 'libknot/zone/zone-tree.c' || echo '$(srcdir)/'`libknot/zone/zone-tree.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-tree.Tpo $(DEPDIR)/zone-tree.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zone-tree.c' object='zone-tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-tree.lo `test -f 'libknot/zone/zone-tree.c' || echo '$(srcdir)/'`libknot/zone/zone-tree.c
+
+zonedb.lo: libknot/zone/zonedb.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb.lo -MD -MP -MF $(DEPDIR)/zonedb.Tpo -c -o zonedb.lo `test -f 'libknot/zone/zonedb.c' || echo '$(srcdir)/'`libknot/zone/zonedb.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb.Tpo $(DEPDIR)/zonedb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zonedb.c' object='zonedb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb.lo `test -f 'libknot/zone/zonedb.c' || echo '$(srcdir)/'`libknot/zone/zonedb.c
+
+node.lo: libknot/zone/node.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node.lo -MD -MP -MF $(DEPDIR)/node.Tpo -c -o node.lo `test -f 'libknot/zone/node.c' || echo '$(srcdir)/'`libknot/zone/node.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node.Tpo $(DEPDIR)/node.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/node.c' object='node.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node.lo `test -f 'libknot/zone/node.c' || echo '$(srcdir)/'`libknot/zone/node.c
+
+dname-table.lo: libknot/zone/dname-table.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname-table.lo -MD -MP -MF $(DEPDIR)/dname-table.Tpo -c -o dname-table.lo `test -f 'libknot/zone/dname-table.c' || echo '$(srcdir)/'`libknot/zone/dname-table.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname-table.Tpo $(DEPDIR)/dname-table.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/dname-table.c' object='dname-table.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname-table.lo `test -f 'libknot/zone/dname-table.c' || echo '$(srcdir)/'`libknot/zone/dname-table.c
+
+hash-functions.lo: libknot/hash/hash-functions.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hash-functions.lo -MD -MP -MF $(DEPDIR)/hash-functions.Tpo -c -o hash-functions.lo `test -f 'libknot/hash/hash-functions.c' || echo '$(srcdir)/'`libknot/hash/hash-functions.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/hash-functions.Tpo $(DEPDIR)/hash-functions.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/hash/hash-functions.c' object='hash-functions.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hash-functions.lo `test -f 'libknot/hash/hash-functions.c' || echo '$(srcdir)/'`libknot/hash/hash-functions.c
+
+cuckoo-hash-table.lo: libknot/hash/cuckoo-hash-table.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cuckoo-hash-table.lo -MD -MP -MF $(DEPDIR)/cuckoo-hash-table.Tpo -c -o cuckoo-hash-table.lo `test -f 'libknot/hash/cuckoo-hash-table.c' || echo '$(srcdir)/'`libknot/hash/cuckoo-hash-table.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cuckoo-hash-table.Tpo $(DEPDIR)/cuckoo-hash-table.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/hash/cuckoo-hash-table.c' object='cuckoo-hash-table.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cuckoo-hash-table.lo `test -f 'libknot/hash/cuckoo-hash-table.c' || echo '$(srcdir)/'`libknot/hash/cuckoo-hash-table.c
+
+universal-system.lo: libknot/hash/universal-system.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT universal-system.lo -MD -MP -MF $(DEPDIR)/universal-system.Tpo -c -o universal-system.lo `test -f 'libknot/hash/universal-system.c' || echo '$(srcdir)/'`libknot/hash/universal-system.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/universal-system.Tpo $(DEPDIR)/universal-system.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/hash/universal-system.c' object='universal-system.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o universal-system.lo `test -f 'libknot/hash/universal-system.c' || echo '$(srcdir)/'`libknot/hash/universal-system.c
+
+name-server.lo: libknot/nameserver/name-server.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT name-server.lo -MD -MP -MF $(DEPDIR)/name-server.Tpo -c -o name-server.lo `test -f 'libknot/nameserver/name-server.c' || echo '$(srcdir)/'`libknot/nameserver/name-server.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/name-server.Tpo $(DEPDIR)/name-server.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/nameserver/name-server.c' object='name-server.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o name-server.lo `test -f 'libknot/nameserver/name-server.c' || echo '$(srcdir)/'`libknot/nameserver/name-server.c
+
+changesets.lo: libknot/updates/changesets.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT changesets.lo -MD -MP -MF $(DEPDIR)/changesets.Tpo -c -o changesets.lo `test -f 'libknot/updates/changesets.c' || echo '$(srcdir)/'`libknot/updates/changesets.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/changesets.Tpo $(DEPDIR)/changesets.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/updates/changesets.c' object='changesets.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o changesets.lo `test -f 'libknot/updates/changesets.c' || echo '$(srcdir)/'`libknot/updates/changesets.c
+
+xfr-in.lo: libknot/updates/xfr-in.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xfr-in.lo -MD -MP -MF $(DEPDIR)/xfr-in.Tpo -c -o xfr-in.lo `test -f 'libknot/updates/xfr-in.c' || echo '$(srcdir)/'`libknot/updates/xfr-in.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xfr-in.Tpo $(DEPDIR)/xfr-in.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/updates/xfr-in.c' object='xfr-in.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xfr-in.lo `test -f 'libknot/updates/xfr-in.c' || echo '$(srcdir)/'`libknot/updates/xfr-in.c
+
+ddns.lo: libknot/updates/ddns.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ddns.lo -MD -MP -MF $(DEPDIR)/ddns.Tpo -c -o ddns.lo `test -f 'libknot/updates/ddns.c' || echo '$(srcdir)/'`libknot/updates/ddns.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ddns.Tpo $(DEPDIR)/ddns.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/updates/ddns.c' object='ddns.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ddns.lo `test -f 'libknot/updates/ddns.c' || echo '$(srcdir)/'`libknot/updates/ddns.c
+
+edns.lo: libknot/edns.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns.lo -MD -MP -MF $(DEPDIR)/edns.Tpo -c -o edns.lo `test -f 'libknot/edns.c' || echo '$(srcdir)/'`libknot/edns.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns.Tpo $(DEPDIR)/edns.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/edns.c' object='edns.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns.lo `test -f 'libknot/edns.c' || echo '$(srcdir)/'`libknot/edns.c
+
+rrset.lo: libknot/rrset.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset.lo -MD -MP -MF $(DEPDIR)/rrset.Tpo -c -o rrset.lo `test -f 'libknot/rrset.c' || echo '$(srcdir)/'`libknot/rrset.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset.Tpo $(DEPDIR)/rrset.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/rrset.c' object='rrset.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset.lo `test -f 'libknot/rrset.c' || echo '$(srcdir)/'`libknot/rrset.c
+
+dname.lo: libknot/dname.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname.lo -MD -MP -MF $(DEPDIR)/dname.Tpo -c -o dname.lo `test -f 'libknot/dname.c' || echo '$(srcdir)/'`libknot/dname.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname.Tpo $(DEPDIR)/dname.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/dname.c' object='dname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname.lo `test -f 'libknot/dname.c' || echo '$(srcdir)/'`libknot/dname.c
+
+rdata.lo: libknot/rdata.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata.lo -MD -MP -MF $(DEPDIR)/rdata.Tpo -c -o rdata.lo `test -f 'libknot/rdata.c' || echo '$(srcdir)/'`libknot/rdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata.Tpo $(DEPDIR)/rdata.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/rdata.c' object='rdata.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata.lo `test -f 'libknot/rdata.c' || echo '$(srcdir)/'`libknot/rdata.c
+
+nsec3.lo: libknot/nsec3.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nsec3.lo -MD -MP -MF $(DEPDIR)/nsec3.Tpo -c -o nsec3.lo `test -f 'libknot/nsec3.c' || echo '$(srcdir)/'`libknot/nsec3.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nsec3.Tpo $(DEPDIR)/nsec3.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/nsec3.c' object='nsec3.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nsec3.lo `test -f 'libknot/nsec3.c' || echo '$(srcdir)/'`libknot/nsec3.c
+
+tsig.lo: libknot/tsig.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tsig.lo -MD -MP -MF $(DEPDIR)/tsig.Tpo -c -o tsig.lo `test -f 'libknot/tsig.c' || echo '$(srcdir)/'`libknot/tsig.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tsig.Tpo $(DEPDIR)/tsig.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/tsig.c' object='tsig.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tsig.lo `test -f 'libknot/tsig.c' || echo '$(srcdir)/'`libknot/tsig.c
+
+tsig-op.lo: libknot/tsig-op.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tsig-op.lo -MD -MP -MF $(DEPDIR)/tsig-op.Tpo -c -o tsig-op.lo `test -f 'libknot/tsig-op.c' || echo '$(srcdir)/'`libknot/tsig-op.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tsig-op.Tpo $(DEPDIR)/tsig-op.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/tsig-op.c' object='tsig-op.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tsig-op.lo `test -f 'libknot/tsig-op.c' || echo '$(srcdir)/'`libknot/tsig-op.c
+
+gatherer.lo: knot/stat/gatherer.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gatherer.lo -MD -MP -MF $(DEPDIR)/gatherer.Tpo -c -o gatherer.lo `test -f 'knot/stat/gatherer.c' || echo '$(srcdir)/'`knot/stat/gatherer.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/gatherer.Tpo $(DEPDIR)/gatherer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/stat/gatherer.c' object='gatherer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gatherer.lo `test -f 'knot/stat/gatherer.c' || echo '$(srcdir)/'`knot/stat/gatherer.c
+
+stat.lo: knot/stat/stat.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stat.lo -MD -MP -MF $(DEPDIR)/stat.Tpo -c -o stat.lo `test -f 'knot/stat/stat.c' || echo '$(srcdir)/'`knot/stat/stat.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/stat.Tpo $(DEPDIR)/stat.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/stat/stat.c' object='stat.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stat.lo `test -f 'knot/stat/stat.c' || echo '$(srcdir)/'`knot/stat/stat.c
+
+log.lo: knot/other/log.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT log.lo -MD -MP -MF $(DEPDIR)/log.Tpo -c -o log.lo `test -f 'knot/other/log.c' || echo '$(srcdir)/'`knot/other/log.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/log.Tpo $(DEPDIR)/log.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/other/log.c' object='log.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o log.lo `test -f 'knot/other/log.c' || echo '$(srcdir)/'`knot/other/log.c
+
+error.lo: knot/other/error.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT error.lo -MD -MP -MF $(DEPDIR)/error.Tpo -c -o error.lo `test -f 'knot/other/error.c' || echo '$(srcdir)/'`knot/other/error.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/error.Tpo $(DEPDIR)/error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/other/error.c' object='error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o error.lo `test -f 'knot/other/error.c' || echo '$(srcdir)/'`knot/other/error.c
+
+conf.lo: knot/conf/conf.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT conf.lo -MD -MP -MF $(DEPDIR)/conf.Tpo -c -o conf.lo `test -f 'knot/conf/conf.c' || echo '$(srcdir)/'`knot/conf/conf.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/conf.Tpo $(DEPDIR)/conf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/conf/conf.c' object='conf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o conf.lo `test -f 'knot/conf/conf.c' || echo '$(srcdir)/'`knot/conf/conf.c
+
+logconf.lo: knot/conf/logconf.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT logconf.lo -MD -MP -MF $(DEPDIR)/logconf.Tpo -c -o logconf.lo `test -f 'knot/conf/logconf.c' || echo '$(srcdir)/'`knot/conf/logconf.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/logconf.Tpo $(DEPDIR)/logconf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/conf/logconf.c' object='logconf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o logconf.lo `test -f 'knot/conf/logconf.c' || echo '$(srcdir)/'`knot/conf/logconf.c
+
+process.lo: knot/ctl/process.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT process.lo -MD -MP -MF $(DEPDIR)/process.Tpo -c -o process.lo `test -f 'knot/ctl/process.c' || echo '$(srcdir)/'`knot/ctl/process.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/process.Tpo $(DEPDIR)/process.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/ctl/process.c' object='process.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o process.lo `test -f 'knot/ctl/process.c' || echo '$(srcdir)/'`knot/ctl/process.c
+
+dthreads.lo: knot/server/dthreads.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dthreads.lo -MD -MP -MF $(DEPDIR)/dthreads.Tpo -c -o dthreads.lo `test -f 'knot/server/dthreads.c' || echo '$(srcdir)/'`knot/server/dthreads.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dthreads.Tpo $(DEPDIR)/dthreads.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/dthreads.c' object='dthreads.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dthreads.lo `test -f 'knot/server/dthreads.c' || echo '$(srcdir)/'`knot/server/dthreads.c
+
+journal.lo: knot/server/journal.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT journal.lo -MD -MP -MF $(DEPDIR)/journal.Tpo -c -o journal.lo `test -f 'knot/server/journal.c' || echo '$(srcdir)/'`knot/server/journal.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/journal.Tpo $(DEPDIR)/journal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/journal.c' object='journal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o journal.lo `test -f 'knot/server/journal.c' || echo '$(srcdir)/'`knot/server/journal.c
+
+socket.lo: knot/server/socket.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.lo -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.lo `test -f 'knot/server/socket.c' || echo '$(srcdir)/'`knot/server/socket.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/socket.c' object='socket.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.lo `test -f 'knot/server/socket.c' || echo '$(srcdir)/'`knot/server/socket.c
+
+server.lo: knot/server/server.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT server.lo -MD -MP -MF $(DEPDIR)/server.Tpo -c -o server.lo `test -f 'knot/server/server.c' || echo '$(srcdir)/'`knot/server/server.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/server.Tpo $(DEPDIR)/server.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/server.c' object='server.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o server.lo `test -f 'knot/server/server.c' || echo '$(srcdir)/'`knot/server/server.c
+
+udp-handler.lo: knot/server/udp-handler.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT udp-handler.lo -MD -MP -MF $(DEPDIR)/udp-handler.Tpo -c -o udp-handler.lo `test -f 'knot/server/udp-handler.c' || echo '$(srcdir)/'`knot/server/udp-handler.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/udp-handler.Tpo $(DEPDIR)/udp-handler.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/udp-handler.c' object='udp-handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o udp-handler.lo `test -f 'knot/server/udp-handler.c' || echo '$(srcdir)/'`knot/server/udp-handler.c
+
+tcp-handler.lo: knot/server/tcp-handler.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tcp-handler.lo -MD -MP -MF $(DEPDIR)/tcp-handler.Tpo -c -o tcp-handler.lo `test -f 'knot/server/tcp-handler.c' || echo '$(srcdir)/'`knot/server/tcp-handler.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tcp-handler.Tpo $(DEPDIR)/tcp-handler.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/tcp-handler.c' object='tcp-handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tcp-handler.lo `test -f 'knot/server/tcp-handler.c' || echo '$(srcdir)/'`knot/server/tcp-handler.c
+
+xfr-handler.lo: knot/server/xfr-handler.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xfr-handler.lo -MD -MP -MF $(DEPDIR)/xfr-handler.Tpo -c -o xfr-handler.lo `test -f 'knot/server/xfr-handler.c' || echo '$(srcdir)/'`knot/server/xfr-handler.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xfr-handler.Tpo $(DEPDIR)/xfr-handler.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/xfr-handler.c' object='xfr-handler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xfr-handler.lo `test -f 'knot/server/xfr-handler.c' || echo '$(srcdir)/'`knot/server/xfr-handler.c
+
+zones.lo: knot/server/zones.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zones.lo -MD -MP -MF $(DEPDIR)/zones.Tpo -c -o zones.lo `test -f 'knot/server/zones.c' || echo '$(srcdir)/'`knot/server/zones.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zones.Tpo $(DEPDIR)/zones.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/zones.c' object='zones.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zones.lo `test -f 'knot/server/zones.c' || echo '$(srcdir)/'`knot/server/zones.c
+
+notify.lo: knot/server/notify.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT notify.lo -MD -MP -MF $(DEPDIR)/notify.Tpo -c -o notify.lo `test -f 'knot/server/notify.c' || echo '$(srcdir)/'`knot/server/notify.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/notify.Tpo $(DEPDIR)/notify.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/server/notify.c' object='notify.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o notify.lo `test -f 'knot/server/notify.c' || echo '$(srcdir)/'`knot/server/notify.c
+
+zone-load.lo: knot/zone/zone-load.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-load.lo -MD -MP -MF $(DEPDIR)/zone-load.Tpo -c -o zone-load.lo `test -f 'knot/zone/zone-load.c' || echo '$(srcdir)/'`knot/zone/zone-load.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-load.Tpo $(DEPDIR)/zone-load.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/zone/zone-load.c' object='zone-load.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-load.lo `test -f 'knot/zone/zone-load.c' || echo '$(srcdir)/'`knot/zone/zone-load.c
+
+zone-dump.lo: knot/zone/zone-dump.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-dump.lo -MD -MP -MF $(DEPDIR)/zone-dump.Tpo -c -o zone-dump.lo `test -f 'knot/zone/zone-dump.c' || echo '$(srcdir)/'`knot/zone/zone-dump.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-dump.Tpo $(DEPDIR)/zone-dump.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/zone/zone-dump.c' object='zone-dump.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-dump.lo `test -f 'knot/zone/zone-dump.c' || echo '$(srcdir)/'`knot/zone/zone-dump.c
+
+zone-dump-text.lo: knot/zone/zone-dump-text.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-dump-text.lo -MD -MP -MF $(DEPDIR)/zone-dump-text.Tpo -c -o zone-dump-text.lo `test -f 'knot/zone/zone-dump-text.c' || echo '$(srcdir)/'`knot/zone/zone-dump-text.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-dump-text.Tpo $(DEPDIR)/zone-dump-text.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/zone/zone-dump-text.c' object='zone-dump-text.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone-dump-text.lo `test -f 'knot/zone/zone-dump-text.c' || echo '$(srcdir)/'`knot/zone/zone-dump-text.c
+
+slab.lo: common/slab/slab.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT slab.lo -MD -MP -MF $(DEPDIR)/slab.Tpo -c -o slab.lo `test -f 'common/slab/slab.c' || echo '$(srcdir)/'`common/slab/slab.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/slab.Tpo $(DEPDIR)/slab.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/slab/slab.c' object='slab.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o slab.lo `test -f 'common/slab/slab.c' || echo '$(srcdir)/'`common/slab/slab.c
+
+malloc.lo: common/slab/malloc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT malloc.lo -MD -MP -MF $(DEPDIR)/malloc.Tpo -c -o malloc.lo `test -f 'common/slab/malloc.c' || echo '$(srcdir)/'`common/slab/malloc.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/malloc.Tpo $(DEPDIR)/malloc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/slab/malloc.c' object='malloc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o malloc.lo `test -f 'common/slab/malloc.c' || echo '$(srcdir)/'`common/slab/malloc.c
+
+tap.lo: common/libtap/tap.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tap.lo -MD -MP -MF $(DEPDIR)/tap.Tpo -c -o tap.lo `test -f 'common/libtap/tap.c' || echo '$(srcdir)/'`common/libtap/tap.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tap.Tpo $(DEPDIR)/tap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/libtap/tap.c' object='tap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tap.lo `test -f 'common/libtap/tap.c' || echo '$(srcdir)/'`common/libtap/tap.c
+
+lists.lo: common/lists.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lists.lo -MD -MP -MF $(DEPDIR)/lists.Tpo -c -o lists.lo `test -f 'common/lists.c' || echo '$(srcdir)/'`common/lists.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/lists.Tpo $(DEPDIR)/lists.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/lists.c' object='lists.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lists.lo `test -f 'common/lists.c' || echo '$(srcdir)/'`common/lists.c
+
+base32.lo: common/base32.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT base32.lo -MD -MP -MF $(DEPDIR)/base32.Tpo -c -o base32.lo `test -f 'common/base32.c' || echo '$(srcdir)/'`common/base32.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/base32.Tpo $(DEPDIR)/base32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/base32.c' object='base32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o base32.lo `test -f 'common/base32.c' || echo '$(srcdir)/'`common/base32.c
+
+print.lo: common/print.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT print.lo -MD -MP -MF $(DEPDIR)/print.Tpo -c -o print.lo `test -f 'common/print.c' || echo '$(srcdir)/'`common/print.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/print.Tpo $(DEPDIR)/print.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/print.c' object='print.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o print.lo `test -f 'common/print.c' || echo '$(srcdir)/'`common/print.c
+
+dynamic-array.lo: common/dynamic-array.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dynamic-array.lo -MD -MP -MF $(DEPDIR)/dynamic-array.Tpo -c -o dynamic-array.lo `test -f 'common/dynamic-array.c' || echo '$(srcdir)/'`common/dynamic-array.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dynamic-array.Tpo $(DEPDIR)/dynamic-array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/dynamic-array.c' object='dynamic-array.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dynamic-array.lo `test -f 'common/dynamic-array.c' || echo '$(srcdir)/'`common/dynamic-array.c
+
+skip-list.lo: common/skip-list.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT skip-list.lo -MD -MP -MF $(DEPDIR)/skip-list.Tpo -c -o skip-list.lo `test -f 'common/skip-list.c' || echo '$(srcdir)/'`common/skip-list.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/skip-list.Tpo $(DEPDIR)/skip-list.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/skip-list.c' object='skip-list.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o skip-list.lo `test -f 'common/skip-list.c' || echo '$(srcdir)/'`common/skip-list.c
+
+base32hex.lo: common/base32hex.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT base32hex.lo -MD -MP -MF $(DEPDIR)/base32hex.Tpo -c -o base32hex.lo `test -f 'common/base32hex.c' || echo '$(srcdir)/'`common/base32hex.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/base32hex.Tpo $(DEPDIR)/base32hex.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/base32hex.c' object='base32hex.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o base32hex.lo `test -f 'common/base32hex.c' || echo '$(srcdir)/'`common/base32hex.c
+
+general-tree.lo: common/general-tree.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT general-tree.lo -MD -MP -MF $(DEPDIR)/general-tree.Tpo -c -o general-tree.lo `test -f 'common/general-tree.c' || echo '$(srcdir)/'`common/general-tree.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/general-tree.Tpo $(DEPDIR)/general-tree.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/general-tree.c' object='general-tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o general-tree.lo `test -f 'common/general-tree.c' || echo '$(srcdir)/'`common/general-tree.c
+
+evqueue.lo: common/evqueue.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT evqueue.lo -MD -MP -MF $(DEPDIR)/evqueue.Tpo -c -o evqueue.lo `test -f 'common/evqueue.c' || echo '$(srcdir)/'`common/evqueue.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/evqueue.Tpo $(DEPDIR)/evqueue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/evqueue.c' object='evqueue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o evqueue.lo `test -f 'common/evqueue.c' || echo '$(srcdir)/'`common/evqueue.c
+
+evsched.lo: common/evsched.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT evsched.lo -MD -MP -MF $(DEPDIR)/evsched.Tpo -c -o evsched.lo `test -f 'common/evsched.c' || echo '$(srcdir)/'`common/evsched.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/evsched.Tpo $(DEPDIR)/evsched.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/evsched.c' object='evsched.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o evsched.lo `test -f 'common/evsched.c' || echo '$(srcdir)/'`common/evsched.c
+
+acl.lo: common/acl.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acl.lo -MD -MP -MF $(DEPDIR)/acl.Tpo -c -o acl.lo `test -f 'common/acl.c' || echo '$(srcdir)/'`common/acl.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/acl.Tpo $(DEPDIR)/acl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/acl.c' object='acl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acl.lo `test -f 'common/acl.c' || echo '$(srcdir)/'`common/acl.c
+
+sockaddr.lo: common/sockaddr.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sockaddr.lo -MD -MP -MF $(DEPDIR)/sockaddr.Tpo -c -o sockaddr.lo `test -f 'common/sockaddr.c' || echo '$(srcdir)/'`common/sockaddr.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/sockaddr.Tpo $(DEPDIR)/sockaddr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/sockaddr.c' object='sockaddr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sockaddr.lo `test -f 'common/sockaddr.c' || echo '$(srcdir)/'`common/sockaddr.c
+
+crc.lo: common/crc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crc.lo -MD -MP -MF $(DEPDIR)/crc.Tpo -c -o crc.lo `test -f 'common/crc.c' || echo '$(srcdir)/'`common/crc.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/crc.Tpo $(DEPDIR)/crc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/crc.c' object='crc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o crc.lo `test -f 'common/crc.c' || echo '$(srcdir)/'`common/crc.c
+
+ref.lo: common/ref.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ref.lo -MD -MP -MF $(DEPDIR)/ref.Tpo -c -o ref.lo `test -f 'common/ref.c' || echo '$(srcdir)/'`common/ref.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ref.Tpo $(DEPDIR)/ref.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/ref.c' object='ref.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ref.lo `test -f 'common/ref.c' || echo '$(srcdir)/'`common/ref.c
+
+errors.lo: common/errors.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT errors.lo -MD -MP -MF $(DEPDIR)/errors.Tpo -c -o errors.lo `test -f 'common/errors.c' || echo '$(srcdir)/'`common/errors.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/errors.Tpo $(DEPDIR)/errors.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/errors.c' object='errors.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o errors.lo `test -f 'common/errors.c' || echo '$(srcdir)/'`common/errors.c
+
+WELL1024a.lo: common/WELL1024a.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT WELL1024a.lo -MD -MP -MF $(DEPDIR)/WELL1024a.Tpo -c -o WELL1024a.lo `test -f 'common/WELL1024a.c' || echo '$(srcdir)/'`common/WELL1024a.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/WELL1024a.Tpo $(DEPDIR)/WELL1024a.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/WELL1024a.c' object='WELL1024a.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o WELL1024a.lo `test -f 'common/WELL1024a.c' || echo '$(srcdir)/'`common/WELL1024a.c
+
+fdset.lo: common/fdset.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset.lo -MD -MP -MF $(DEPDIR)/fdset.Tpo -c -o fdset.lo `test -f 'common/fdset.c' || echo '$(srcdir)/'`common/fdset.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset.Tpo $(DEPDIR)/fdset.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/fdset.c' object='fdset.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset.lo `test -f 'common/fdset.c' || echo '$(srcdir)/'`common/fdset.c
+
+fdset_poll.lo: common/fdset_poll.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_poll.lo -MD -MP -MF $(DEPDIR)/fdset_poll.Tpo -c -o fdset_poll.lo `test -f 'common/fdset_poll.c' || echo '$(srcdir)/'`common/fdset_poll.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_poll.Tpo $(DEPDIR)/fdset_poll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/fdset_poll.c' object='fdset_poll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_poll.lo `test -f 'common/fdset_poll.c' || echo '$(srcdir)/'`common/fdset_poll.c
+
+fdset_kqueue.lo: common/fdset_kqueue.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_kqueue.lo -MD -MP -MF $(DEPDIR)/fdset_kqueue.Tpo -c -o fdset_kqueue.lo `test -f 'common/fdset_kqueue.c' || echo '$(srcdir)/'`common/fdset_kqueue.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_kqueue.Tpo $(DEPDIR)/fdset_kqueue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/fdset_kqueue.c' object='fdset_kqueue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_kqueue.lo `test -f 'common/fdset_kqueue.c' || echo '$(srcdir)/'`common/fdset_kqueue.c
+
+fdset_epoll.lo: common/fdset_epoll.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_epoll.lo -MD -MP -MF $(DEPDIR)/fdset_epoll.Tpo -c -o fdset_epoll.lo `test -f 'common/fdset_epoll.c' || echo '$(srcdir)/'`common/fdset_epoll.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_epoll.Tpo $(DEPDIR)/fdset_epoll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/fdset_epoll.c' object='fdset_epoll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_epoll.lo `test -f 'common/fdset_epoll.c' || echo '$(srcdir)/'`common/fdset_epoll.c
+
+zcompile_main.o: zcompile/zcompile_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile_main.o -MD -MP -MF $(DEPDIR)/zcompile_main.Tpo -c -o zcompile_main.o `test -f 'zcompile/zcompile_main.c' || echo '$(srcdir)/'`zcompile/zcompile_main.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile_main.Tpo $(DEPDIR)/zcompile_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile_main.c' object='zcompile_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile_main.o `test -f 'zcompile/zcompile_main.c' || echo '$(srcdir)/'`zcompile/zcompile_main.c
+
+zcompile_main.obj: zcompile/zcompile_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile_main.obj -MD -MP -MF $(DEPDIR)/zcompile_main.Tpo -c -o zcompile_main.obj `if test -f 'zcompile/zcompile_main.c'; then $(CYGPATH_W) 'zcompile/zcompile_main.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile_main.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile_main.Tpo $(DEPDIR)/zcompile_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile_main.c' object='zcompile_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile_main.obj `if test -f 'zcompile/zcompile_main.c'; then $(CYGPATH_W) 'zcompile/zcompile_main.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile_main.c'; fi`
+
+zcompile-error.o: zcompile/zcompile-error.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile-error.o -MD -MP -MF $(DEPDIR)/zcompile-error.Tpo -c -o zcompile-error.o `test -f 'zcompile/zcompile-error.c' || echo '$(srcdir)/'`zcompile/zcompile-error.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile-error.Tpo $(DEPDIR)/zcompile-error.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile-error.c' object='zcompile-error.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile-error.o `test -f 'zcompile/zcompile-error.c' || echo '$(srcdir)/'`zcompile/zcompile-error.c
+
+zcompile-error.obj: zcompile/zcompile-error.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile-error.obj -MD -MP -MF $(DEPDIR)/zcompile-error.Tpo -c -o zcompile-error.obj `if test -f 'zcompile/zcompile-error.c'; then $(CYGPATH_W) 'zcompile/zcompile-error.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile-error.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile-error.Tpo $(DEPDIR)/zcompile-error.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile-error.c' object='zcompile-error.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile-error.obj `if test -f 'zcompile/zcompile-error.c'; then $(CYGPATH_W) 'zcompile/zcompile-error.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile-error.c'; fi`
+
+zcompile.o: zcompile/zcompile.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile.o -MD -MP -MF $(DEPDIR)/zcompile.Tpo -c -o zcompile.o `test -f 'zcompile/zcompile.c' || echo '$(srcdir)/'`zcompile/zcompile.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile.Tpo $(DEPDIR)/zcompile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile.c' object='zcompile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile.o `test -f 'zcompile/zcompile.c' || echo '$(srcdir)/'`zcompile/zcompile.c
+
+zcompile.obj: zcompile/zcompile.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile.obj -MD -MP -MF $(DEPDIR)/zcompile.Tpo -c -o zcompile.obj `if test -f 'zcompile/zcompile.c'; then $(CYGPATH_W) 'zcompile/zcompile.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile.Tpo $(DEPDIR)/zcompile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/zcompile.c' object='zcompile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zcompile.obj `if test -f 'zcompile/zcompile.c'; then $(CYGPATH_W) 'zcompile/zcompile.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/zcompile.c'; fi`
+
+parser-util.o: zcompile/parser-util.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser-util.o -MD -MP -MF $(DEPDIR)/parser-util.Tpo -c -o parser-util.o `test -f 'zcompile/parser-util.c' || echo '$(srcdir)/'`zcompile/parser-util.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/parser-util.Tpo $(DEPDIR)/parser-util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/parser-util.c' object='parser-util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser-util.o `test -f 'zcompile/parser-util.c' || echo '$(srcdir)/'`zcompile/parser-util.c
+
+parser-util.obj: zcompile/parser-util.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser-util.obj -MD -MP -MF $(DEPDIR)/parser-util.Tpo -c -o parser-util.obj `if test -f 'zcompile/parser-util.c'; then $(CYGPATH_W) 'zcompile/parser-util.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/parser-util.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/parser-util.Tpo $(DEPDIR)/parser-util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/parser-util.c' object='parser-util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser-util.obj `if test -f 'zcompile/parser-util.c'; then $(CYGPATH_W) 'zcompile/parser-util.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/parser-util.c'; fi`
+
+parser-descriptor.o: zcompile/parser-descriptor.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser-descriptor.o -MD -MP -MF $(DEPDIR)/parser-descriptor.Tpo -c -o parser-descriptor.o `test -f 'zcompile/parser-descriptor.c' || echo '$(srcdir)/'`zcompile/parser-descriptor.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/parser-descriptor.Tpo $(DEPDIR)/parser-descriptor.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/parser-descriptor.c' object='parser-descriptor.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser-descriptor.o `test -f 'zcompile/parser-descriptor.c' || echo '$(srcdir)/'`zcompile/parser-descriptor.c
+
+parser-descriptor.obj: zcompile/parser-descriptor.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT parser-descriptor.obj -MD -MP -MF $(DEPDIR)/parser-descriptor.Tpo -c -o parser-descriptor.obj `if test -f 'zcompile/parser-descriptor.c'; then $(CYGPATH_W) 'zcompile/parser-descriptor.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/parser-descriptor.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/parser-descriptor.Tpo $(DEPDIR)/parser-descriptor.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/parser-descriptor.c' object='parser-descriptor.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o parser-descriptor.obj `if test -f 'zcompile/parser-descriptor.c'; then $(CYGPATH_W) 'zcompile/parser-descriptor.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/parser-descriptor.c'; fi`
+
+knotc_main.o: knot/ctl/knotc_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knotc_main.o -MD -MP -MF $(DEPDIR)/knotc_main.Tpo -c -o knotc_main.o `test -f 'knot/ctl/knotc_main.c' || echo '$(srcdir)/'`knot/ctl/knotc_main.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/knotc_main.Tpo $(DEPDIR)/knotc_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/ctl/knotc_main.c' object='knotc_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knotc_main.o `test -f 'knot/ctl/knotc_main.c' || echo '$(srcdir)/'`knot/ctl/knotc_main.c
+
+knotc_main.obj: knot/ctl/knotc_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT knotc_main.obj -MD -MP -MF $(DEPDIR)/knotc_main.Tpo -c -o knotc_main.obj `if test -f 'knot/ctl/knotc_main.c'; then $(CYGPATH_W) 'knot/ctl/knotc_main.c'; else $(CYGPATH_W) '$(srcdir)/knot/ctl/knotc_main.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/knotc_main.Tpo $(DEPDIR)/knotc_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/ctl/knotc_main.c' object='knotc_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o knotc_main.obj `if test -f 'knot/ctl/knotc_main.c'; then $(CYGPATH_W) 'knot/ctl/knotc_main.c'; else $(CYGPATH_W) '$(srcdir)/knot/ctl/knotc_main.c'; fi`
+
+main.o: knot/main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT main.o -MD -MP -MF $(DEPDIR)/main.Tpo -c -o main.o `test -f 'knot/main.c' || echo '$(srcdir)/'`knot/main.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/main.Tpo $(DEPDIR)/main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/main.c' object='main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o main.o `test -f 'knot/main.c' || echo '$(srcdir)/'`knot/main.c
+
+main.obj: knot/main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT main.obj -MD -MP -MF $(DEPDIR)/main.Tpo -c -o main.obj `if test -f 'knot/main.c'; then $(CYGPATH_W) 'knot/main.c'; else $(CYGPATH_W) '$(srcdir)/knot/main.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/main.Tpo $(DEPDIR)/main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/main.c' object='main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o main.obj `if test -f 'knot/main.c'; then $(CYGPATH_W) 'knot/main.c'; else $(CYGPATH_W) '$(srcdir)/knot/main.c'; fi`
+
+acl_tests.o: tests/common/acl_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acl_tests.o -MD -MP -MF $(DEPDIR)/acl_tests.Tpo -c -o acl_tests.o `test -f 'tests/common/acl_tests.c' || echo '$(srcdir)/'`tests/common/acl_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/acl_tests.Tpo $(DEPDIR)/acl_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/acl_tests.c' object='acl_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acl_tests.o `test -f 'tests/common/acl_tests.c' || echo '$(srcdir)/'`tests/common/acl_tests.c
+
+acl_tests.obj: tests/common/acl_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acl_tests.obj -MD -MP -MF $(DEPDIR)/acl_tests.Tpo -c -o acl_tests.obj `if test -f 'tests/common/acl_tests.c'; then $(CYGPATH_W) 'tests/common/acl_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/acl_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/acl_tests.Tpo $(DEPDIR)/acl_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/acl_tests.c' object='acl_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acl_tests.obj `if test -f 'tests/common/acl_tests.c'; then $(CYGPATH_W) 'tests/common/acl_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/acl_tests.c'; fi`
+
+da_tests.o: tests/common/da_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT da_tests.o -MD -MP -MF $(DEPDIR)/da_tests.Tpo -c -o da_tests.o `test -f 'tests/common/da_tests.c' || echo '$(srcdir)/'`tests/common/da_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/da_tests.Tpo $(DEPDIR)/da_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/da_tests.c' object='da_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o da_tests.o `test -f 'tests/common/da_tests.c' || echo '$(srcdir)/'`tests/common/da_tests.c
+
+da_tests.obj: tests/common/da_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT da_tests.obj -MD -MP -MF $(DEPDIR)/da_tests.Tpo -c -o da_tests.obj `if test -f 'tests/common/da_tests.c'; then $(CYGPATH_W) 'tests/common/da_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/da_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/da_tests.Tpo $(DEPDIR)/da_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/da_tests.c' object='da_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o da_tests.obj `if test -f 'tests/common/da_tests.c'; then $(CYGPATH_W) 'tests/common/da_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/da_tests.c'; fi`
+
+events_tests.o: tests/common/events_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT events_tests.o -MD -MP -MF $(DEPDIR)/events_tests.Tpo -c -o events_tests.o `test -f 'tests/common/events_tests.c' || echo '$(srcdir)/'`tests/common/events_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/events_tests.Tpo $(DEPDIR)/events_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/events_tests.c' object='events_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o events_tests.o `test -f 'tests/common/events_tests.c' || echo '$(srcdir)/'`tests/common/events_tests.c
+
+events_tests.obj: tests/common/events_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT events_tests.obj -MD -MP -MF $(DEPDIR)/events_tests.Tpo -c -o events_tests.obj `if test -f 'tests/common/events_tests.c'; then $(CYGPATH_W) 'tests/common/events_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/events_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/events_tests.Tpo $(DEPDIR)/events_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/events_tests.c' object='events_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o events_tests.obj `if test -f 'tests/common/events_tests.c'; then $(CYGPATH_W) 'tests/common/events_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/events_tests.c'; fi`
+
+skiplist_tests.o: tests/common/skiplist_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT skiplist_tests.o -MD -MP -MF $(DEPDIR)/skiplist_tests.Tpo -c -o skiplist_tests.o `test -f 'tests/common/skiplist_tests.c' || echo '$(srcdir)/'`tests/common/skiplist_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/skiplist_tests.Tpo $(DEPDIR)/skiplist_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/skiplist_tests.c' object='skiplist_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o skiplist_tests.o `test -f 'tests/common/skiplist_tests.c' || echo '$(srcdir)/'`tests/common/skiplist_tests.c
+
+skiplist_tests.obj: tests/common/skiplist_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT skiplist_tests.obj -MD -MP -MF $(DEPDIR)/skiplist_tests.Tpo -c -o skiplist_tests.obj `if test -f 'tests/common/skiplist_tests.c'; then $(CYGPATH_W) 'tests/common/skiplist_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/skiplist_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/skiplist_tests.Tpo $(DEPDIR)/skiplist_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/skiplist_tests.c' object='skiplist_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o skiplist_tests.obj `if test -f 'tests/common/skiplist_tests.c'; then $(CYGPATH_W) 'tests/common/skiplist_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/skiplist_tests.c'; fi`
+
+slab_tests.o: tests/common/slab_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT slab_tests.o -MD -MP -MF $(DEPDIR)/slab_tests.Tpo -c -o slab_tests.o `test -f 'tests/common/slab_tests.c' || echo '$(srcdir)/'`tests/common/slab_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/slab_tests.Tpo $(DEPDIR)/slab_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/slab_tests.c' object='slab_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o slab_tests.o `test -f 'tests/common/slab_tests.c' || echo '$(srcdir)/'`tests/common/slab_tests.c
+
+slab_tests.obj: tests/common/slab_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT slab_tests.obj -MD -MP -MF $(DEPDIR)/slab_tests.Tpo -c -o slab_tests.obj `if test -f 'tests/common/slab_tests.c'; then $(CYGPATH_W) 'tests/common/slab_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/slab_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/slab_tests.Tpo $(DEPDIR)/slab_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/slab_tests.c' object='slab_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o slab_tests.obj `if test -f 'tests/common/slab_tests.c'; then $(CYGPATH_W) 'tests/common/slab_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/slab_tests.c'; fi`
+
+fdset_tests.o: tests/common/fdset_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_tests.o -MD -MP -MF $(DEPDIR)/fdset_tests.Tpo -c -o fdset_tests.o `test -f 'tests/common/fdset_tests.c' || echo '$(srcdir)/'`tests/common/fdset_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_tests.Tpo $(DEPDIR)/fdset_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/fdset_tests.c' object='fdset_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_tests.o `test -f 'tests/common/fdset_tests.c' || echo '$(srcdir)/'`tests/common/fdset_tests.c
+
+fdset_tests.obj: tests/common/fdset_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fdset_tests.obj -MD -MP -MF $(DEPDIR)/fdset_tests.Tpo -c -o fdset_tests.obj `if test -f 'tests/common/fdset_tests.c'; then $(CYGPATH_W) 'tests/common/fdset_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/fdset_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/fdset_tests.Tpo $(DEPDIR)/fdset_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/fdset_tests.c' object='fdset_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_tests.obj `if test -f 'tests/common/fdset_tests.c'; then $(CYGPATH_W) 'tests/common/fdset_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/fdset_tests.c'; fi`
+
+conf_tests.o: tests/knot/conf_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT conf_tests.o -MD -MP -MF $(DEPDIR)/conf_tests.Tpo -c -o conf_tests.o `test -f 'tests/knot/conf_tests.c' || echo '$(srcdir)/'`tests/knot/conf_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/conf_tests.Tpo $(DEPDIR)/conf_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/conf_tests.c' object='conf_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o conf_tests.o `test -f 'tests/knot/conf_tests.c' || echo '$(srcdir)/'`tests/knot/conf_tests.c
+
+conf_tests.obj: tests/knot/conf_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT conf_tests.obj -MD -MP -MF $(DEPDIR)/conf_tests.Tpo -c -o conf_tests.obj `if test -f 'tests/knot/conf_tests.c'; then $(CYGPATH_W) 'tests/knot/conf_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/conf_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/conf_tests.Tpo $(DEPDIR)/conf_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/conf_tests.c' object='conf_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o conf_tests.obj `if test -f 'tests/knot/conf_tests.c'; then $(CYGPATH_W) 'tests/knot/conf_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/conf_tests.c'; fi`
+
+dthreads_tests.o: tests/knot/dthreads_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dthreads_tests.o -MD -MP -MF $(DEPDIR)/dthreads_tests.Tpo -c -o dthreads_tests.o `test -f 'tests/knot/dthreads_tests.c' || echo '$(srcdir)/'`tests/knot/dthreads_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dthreads_tests.Tpo $(DEPDIR)/dthreads_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/dthreads_tests.c' object='dthreads_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dthreads_tests.o `test -f 'tests/knot/dthreads_tests.c' || echo '$(srcdir)/'`tests/knot/dthreads_tests.c
+
+dthreads_tests.obj: tests/knot/dthreads_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dthreads_tests.obj -MD -MP -MF $(DEPDIR)/dthreads_tests.Tpo -c -o dthreads_tests.obj `if test -f 'tests/knot/dthreads_tests.c'; then $(CYGPATH_W) 'tests/knot/dthreads_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/dthreads_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dthreads_tests.Tpo $(DEPDIR)/dthreads_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/dthreads_tests.c' object='dthreads_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dthreads_tests.obj `if test -f 'tests/knot/dthreads_tests.c'; then $(CYGPATH_W) 'tests/knot/dthreads_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/dthreads_tests.c'; fi`
+
+journal_tests.o: tests/knot/journal_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT journal_tests.o -MD -MP -MF $(DEPDIR)/journal_tests.Tpo -c -o journal_tests.o `test -f 'tests/knot/journal_tests.c' || echo '$(srcdir)/'`tests/knot/journal_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/journal_tests.Tpo $(DEPDIR)/journal_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/journal_tests.c' object='journal_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o journal_tests.o `test -f 'tests/knot/journal_tests.c' || echo '$(srcdir)/'`tests/knot/journal_tests.c
+
+journal_tests.obj: tests/knot/journal_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT journal_tests.obj -MD -MP -MF $(DEPDIR)/journal_tests.Tpo -c -o journal_tests.obj `if test -f 'tests/knot/journal_tests.c'; then $(CYGPATH_W) 'tests/knot/journal_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/journal_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/journal_tests.Tpo $(DEPDIR)/journal_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/journal_tests.c' object='journal_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o journal_tests.obj `if test -f 'tests/knot/journal_tests.c'; then $(CYGPATH_W) 'tests/knot/journal_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/journal_tests.c'; fi`
+
+server_tests.o: tests/knot/server_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT server_tests.o -MD -MP -MF $(DEPDIR)/server_tests.Tpo -c -o server_tests.o `test -f 'tests/knot/server_tests.c' || echo '$(srcdir)/'`tests/knot/server_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/server_tests.Tpo $(DEPDIR)/server_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/server_tests.c' object='server_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o server_tests.o `test -f 'tests/knot/server_tests.c' || echo '$(srcdir)/'`tests/knot/server_tests.c
+
+server_tests.obj: tests/knot/server_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT server_tests.obj -MD -MP -MF $(DEPDIR)/server_tests.Tpo -c -o server_tests.obj `if test -f 'tests/knot/server_tests.c'; then $(CYGPATH_W) 'tests/knot/server_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/server_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/server_tests.Tpo $(DEPDIR)/server_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/knot/server_tests.c' object='server_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o server_tests.obj `if test -f 'tests/knot/server_tests.c'; then $(CYGPATH_W) 'tests/knot/server_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/knot/server_tests.c'; fi`
+
+unittests_main.o: tests/unittests_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_main.o -MD -MP -MF $(DEPDIR)/unittests_main.Tpo -c -o unittests_main.o `test -f 'tests/unittests_main.c' || echo '$(srcdir)/'`tests/unittests_main.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_main.Tpo $(DEPDIR)/unittests_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/unittests_main.c' object='unittests_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_main.o `test -f 'tests/unittests_main.c' || echo '$(srcdir)/'`tests/unittests_main.c
+
+unittests_main.obj: tests/unittests_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_main.obj -MD -MP -MF $(DEPDIR)/unittests_main.Tpo -c -o unittests_main.obj `if test -f 'tests/unittests_main.c'; then $(CYGPATH_W) 'tests/unittests_main.c'; else $(CYGPATH_W) '$(srcdir)/tests/unittests_main.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_main.Tpo $(DEPDIR)/unittests_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/unittests_main.c' object='unittests_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_main.obj `if test -f 'tests/unittests_main.c'; then $(CYGPATH_W) 'tests/unittests_main.c'; else $(CYGPATH_W) '$(srcdir)/tests/unittests_main.c'; fi`
+
+cuckoo_tests.o: tests/libknot/libknot/cuckoo_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cuckoo_tests.o -MD -MP -MF $(DEPDIR)/cuckoo_tests.Tpo -c -o cuckoo_tests.o `test -f 'tests/libknot/libknot/cuckoo_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/cuckoo_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cuckoo_tests.Tpo $(DEPDIR)/cuckoo_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/cuckoo_tests.c' object='cuckoo_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cuckoo_tests.o `test -f 'tests/libknot/libknot/cuckoo_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/cuckoo_tests.c
+
+cuckoo_tests.obj: tests/libknot/libknot/cuckoo_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cuckoo_tests.obj -MD -MP -MF $(DEPDIR)/cuckoo_tests.Tpo -c -o cuckoo_tests.obj `if test -f 'tests/libknot/libknot/cuckoo_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/cuckoo_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/cuckoo_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cuckoo_tests.Tpo $(DEPDIR)/cuckoo_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/cuckoo_tests.c' object='cuckoo_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cuckoo_tests.obj `if test -f 'tests/libknot/libknot/cuckoo_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/cuckoo_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/cuckoo_tests.c'; fi`
+
+response_tests.o: tests/libknot/libknot/response_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response_tests.o -MD -MP -MF $(DEPDIR)/response_tests.Tpo -c -o response_tests.o `test -f 'tests/libknot/libknot/response_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/response_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response_tests.Tpo $(DEPDIR)/response_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/response_tests.c' object='response_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response_tests.o `test -f 'tests/libknot/libknot/response_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/response_tests.c
+
+response_tests.obj: tests/libknot/libknot/response_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response_tests.obj -MD -MP -MF $(DEPDIR)/response_tests.Tpo -c -o response_tests.obj `if test -f 'tests/libknot/libknot/response_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/response_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/response_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response_tests.Tpo $(DEPDIR)/response_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/response_tests.c' object='response_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response_tests.obj `if test -f 'tests/libknot/libknot/response_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/response_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/response_tests.c'; fi`
+
+dname_tests.o: tests/libknot/libknot/dname_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_tests.o -MD -MP -MF $(DEPDIR)/dname_tests.Tpo -c -o dname_tests.o `test -f 'tests/libknot/libknot/dname_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/dname_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_tests.Tpo $(DEPDIR)/dname_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/dname_tests.c' object='dname_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_tests.o `test -f 'tests/libknot/libknot/dname_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/dname_tests.c
+
+dname_tests.obj: tests/libknot/libknot/dname_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_tests.obj -MD -MP -MF $(DEPDIR)/dname_tests.Tpo -c -o dname_tests.obj `if test -f 'tests/libknot/libknot/dname_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/dname_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/dname_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_tests.Tpo $(DEPDIR)/dname_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/dname_tests.c' object='dname_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_tests.obj `if test -f 'tests/libknot/libknot/dname_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/dname_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/dname_tests.c'; fi`
+
+dname_table_tests.o: tests/libknot/libknot/dname_table_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_table_tests.o -MD -MP -MF $(DEPDIR)/dname_table_tests.Tpo -c -o dname_table_tests.o `test -f 'tests/libknot/libknot/dname_table_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/dname_table_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_table_tests.Tpo $(DEPDIR)/dname_table_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/dname_table_tests.c' object='dname_table_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_table_tests.o `test -f 'tests/libknot/libknot/dname_table_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/dname_table_tests.c
+
+dname_table_tests.obj: tests/libknot/libknot/dname_table_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_table_tests.obj -MD -MP -MF $(DEPDIR)/dname_table_tests.Tpo -c -o dname_table_tests.obj `if test -f 'tests/libknot/libknot/dname_table_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/dname_table_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/dname_table_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_table_tests.Tpo $(DEPDIR)/dname_table_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/dname_table_tests.c' object='dname_table_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_table_tests.obj `if test -f 'tests/libknot/libknot/dname_table_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/dname_table_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/dname_table_tests.c'; fi`
+
+nsec3_tests.o: tests/libknot/libknot/nsec3_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nsec3_tests.o -MD -MP -MF $(DEPDIR)/nsec3_tests.Tpo -c -o nsec3_tests.o `test -f 'tests/libknot/libknot/nsec3_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/nsec3_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nsec3_tests.Tpo $(DEPDIR)/nsec3_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/nsec3_tests.c' object='nsec3_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nsec3_tests.o `test -f 'tests/libknot/libknot/nsec3_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/nsec3_tests.c
+
+nsec3_tests.obj: tests/libknot/libknot/nsec3_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nsec3_tests.obj -MD -MP -MF $(DEPDIR)/nsec3_tests.Tpo -c -o nsec3_tests.obj `if test -f 'tests/libknot/libknot/nsec3_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/nsec3_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/nsec3_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nsec3_tests.Tpo $(DEPDIR)/nsec3_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/nsec3_tests.c' object='nsec3_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nsec3_tests.obj `if test -f 'tests/libknot/libknot/nsec3_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/nsec3_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/nsec3_tests.c'; fi`
+
+packet_tests.o: tests/libknot/libknot/packet_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet_tests.o -MD -MP -MF $(DEPDIR)/packet_tests.Tpo -c -o packet_tests.o `test -f 'tests/libknot/libknot/packet_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/packet_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet_tests.Tpo $(DEPDIR)/packet_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/packet_tests.c' object='packet_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet_tests.o `test -f 'tests/libknot/libknot/packet_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/packet_tests.c
+
+packet_tests.obj: tests/libknot/libknot/packet_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet_tests.obj -MD -MP -MF $(DEPDIR)/packet_tests.Tpo -c -o packet_tests.obj `if test -f 'tests/libknot/libknot/packet_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/packet_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/packet_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet_tests.Tpo $(DEPDIR)/packet_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/packet_tests.c' object='packet_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet_tests.obj `if test -f 'tests/libknot/libknot/packet_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/packet_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/packet_tests.c'; fi`
+
+query_tests.o: tests/libknot/libknot/query_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT query_tests.o -MD -MP -MF $(DEPDIR)/query_tests.Tpo -c -o query_tests.o `test -f 'tests/libknot/libknot/query_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/query_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/query_tests.Tpo $(DEPDIR)/query_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/query_tests.c' object='query_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o query_tests.o `test -f 'tests/libknot/libknot/query_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/query_tests.c
+
+query_tests.obj: tests/libknot/libknot/query_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT query_tests.obj -MD -MP -MF $(DEPDIR)/query_tests.Tpo -c -o query_tests.obj `if test -f 'tests/libknot/libknot/query_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/query_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/query_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/query_tests.Tpo $(DEPDIR)/query_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/query_tests.c' object='query_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o query_tests.obj `if test -f 'tests/libknot/libknot/query_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/query_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/query_tests.c'; fi`
+
+edns_tests.o: tests/libknot/libknot/edns_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns_tests.o -MD -MP -MF $(DEPDIR)/edns_tests.Tpo -c -o edns_tests.o `test -f 'tests/libknot/libknot/edns_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/edns_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns_tests.Tpo $(DEPDIR)/edns_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/edns_tests.c' object='edns_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns_tests.o `test -f 'tests/libknot/libknot/edns_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/edns_tests.c
+
+edns_tests.obj: tests/libknot/libknot/edns_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns_tests.obj -MD -MP -MF $(DEPDIR)/edns_tests.Tpo -c -o edns_tests.obj `if test -f 'tests/libknot/libknot/edns_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/edns_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/edns_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns_tests.Tpo $(DEPDIR)/edns_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/edns_tests.c' object='edns_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns_tests.obj `if test -f 'tests/libknot/libknot/edns_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/edns_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/edns_tests.c'; fi`
+
+node_tests.o: tests/libknot/libknot/node_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node_tests.o -MD -MP -MF $(DEPDIR)/node_tests.Tpo -c -o node_tests.o `test -f 'tests/libknot/libknot/node_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/node_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node_tests.Tpo $(DEPDIR)/node_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/node_tests.c' object='node_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node_tests.o `test -f 'tests/libknot/libknot/node_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/node_tests.c
+
+node_tests.obj: tests/libknot/libknot/node_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node_tests.obj -MD -MP -MF $(DEPDIR)/node_tests.Tpo -c -o node_tests.obj `if test -f 'tests/libknot/libknot/node_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/node_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/node_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node_tests.Tpo $(DEPDIR)/node_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/node_tests.c' object='node_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node_tests.obj `if test -f 'tests/libknot/libknot/node_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/node_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/node_tests.c'; fi`
+
+rdata_tests.o: tests/libknot/libknot/rdata_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_tests.o -MD -MP -MF $(DEPDIR)/rdata_tests.Tpo -c -o rdata_tests.o `test -f 'tests/libknot/libknot/rdata_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/rdata_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata_tests.Tpo $(DEPDIR)/rdata_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/rdata_tests.c' object='rdata_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_tests.o `test -f 'tests/libknot/libknot/rdata_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/rdata_tests.c
+
+rdata_tests.obj: tests/libknot/libknot/rdata_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_tests.obj -MD -MP -MF $(DEPDIR)/rdata_tests.Tpo -c -o rdata_tests.obj `if test -f 'tests/libknot/libknot/rdata_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/rdata_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/rdata_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata_tests.Tpo $(DEPDIR)/rdata_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/rdata_tests.c' object='rdata_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_tests.obj `if test -f 'tests/libknot/libknot/rdata_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/rdata_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/rdata_tests.c'; fi`
+
+rrset_tests.o: tests/libknot/libknot/rrset_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset_tests.o -MD -MP -MF $(DEPDIR)/rrset_tests.Tpo -c -o rrset_tests.o `test -f 'tests/libknot/libknot/rrset_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/rrset_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset_tests.Tpo $(DEPDIR)/rrset_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/rrset_tests.c' object='rrset_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset_tests.o `test -f 'tests/libknot/libknot/rrset_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/rrset_tests.c
+
+rrset_tests.obj: tests/libknot/libknot/rrset_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset_tests.obj -MD -MP -MF $(DEPDIR)/rrset_tests.Tpo -c -o rrset_tests.obj `if test -f 'tests/libknot/libknot/rrset_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/rrset_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/rrset_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset_tests.Tpo $(DEPDIR)/rrset_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/rrset_tests.c' object='rrset_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset_tests.obj `if test -f 'tests/libknot/libknot/rrset_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/rrset_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/rrset_tests.c'; fi`
+
+zone_tests.o: tests/libknot/libknot/zone_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tests.o -MD -MP -MF $(DEPDIR)/zone_tests.Tpo -c -o zone_tests.o `test -f 'tests/libknot/libknot/zone_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zone_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tests.Tpo $(DEPDIR)/zone_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zone_tests.c' object='zone_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tests.o `test -f 'tests/libknot/libknot/zone_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zone_tests.c
+
+zone_tests.obj: tests/libknot/libknot/zone_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tests.obj -MD -MP -MF $(DEPDIR)/zone_tests.Tpo -c -o zone_tests.obj `if test -f 'tests/libknot/libknot/zone_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zone_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zone_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tests.Tpo $(DEPDIR)/zone_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zone_tests.c' object='zone_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tests.obj `if test -f 'tests/libknot/libknot/zone_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zone_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zone_tests.c'; fi`
+
+zone_tree_tests.o: tests/libknot/libknot/zone_tree_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tree_tests.o -MD -MP -MF $(DEPDIR)/zone_tree_tests.Tpo -c -o zone_tree_tests.o `test -f 'tests/libknot/libknot/zone_tree_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zone_tree_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tree_tests.Tpo $(DEPDIR)/zone_tree_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zone_tree_tests.c' object='zone_tree_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tree_tests.o `test -f 'tests/libknot/libknot/zone_tree_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zone_tree_tests.c
+
+zone_tree_tests.obj: tests/libknot/libknot/zone_tree_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tree_tests.obj -MD -MP -MF $(DEPDIR)/zone_tree_tests.Tpo -c -o zone_tree_tests.obj `if test -f 'tests/libknot/libknot/zone_tree_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zone_tree_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zone_tree_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tree_tests.Tpo $(DEPDIR)/zone_tree_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zone_tree_tests.c' object='zone_tree_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tree_tests.obj `if test -f 'tests/libknot/libknot/zone_tree_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zone_tree_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zone_tree_tests.c'; fi`
+
+zonedb_tests.o: tests/libknot/libknot/zonedb_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb_tests.o -MD -MP -MF $(DEPDIR)/zonedb_tests.Tpo -c -o zonedb_tests.o `test -f 'tests/libknot/libknot/zonedb_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zonedb_tests.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb_tests.Tpo $(DEPDIR)/zonedb_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zonedb_tests.c' object='zonedb_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb_tests.o `test -f 'tests/libknot/libknot/zonedb_tests.c' || echo '$(srcdir)/'`tests/libknot/libknot/zonedb_tests.c
+
+zonedb_tests.obj: tests/libknot/libknot/zonedb_tests.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb_tests.obj -MD -MP -MF $(DEPDIR)/zonedb_tests.Tpo -c -o zonedb_tests.obj `if test -f 'tests/libknot/libknot/zonedb_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zonedb_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zonedb_tests.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb_tests.Tpo $(DEPDIR)/zonedb_tests.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/libknot/zonedb_tests.c' object='zonedb_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb_tests.obj `if test -f 'tests/libknot/libknot/zonedb_tests.c'; then $(CYGPATH_W) 'tests/libknot/libknot/zonedb_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/libknot/zonedb_tests.c'; fi`
+
+unittests_libknot.o: tests/libknot/unittests_libknot.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_libknot.o -MD -MP -MF $(DEPDIR)/unittests_libknot.Tpo -c -o unittests_libknot.o `test -f 'tests/libknot/unittests_libknot.c' || echo '$(srcdir)/'`tests/libknot/unittests_libknot.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_libknot.Tpo $(DEPDIR)/unittests_libknot.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/unittests_libknot.c' object='unittests_libknot.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_libknot.o `test -f 'tests/libknot/unittests_libknot.c' || echo '$(srcdir)/'`tests/libknot/unittests_libknot.c
+
+unittests_libknot.obj: tests/libknot/unittests_libknot.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_libknot.obj -MD -MP -MF $(DEPDIR)/unittests_libknot.Tpo -c -o unittests_libknot.obj `if test -f 'tests/libknot/unittests_libknot.c'; then $(CYGPATH_W) 'tests/libknot/unittests_libknot.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/unittests_libknot.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_libknot.Tpo $(DEPDIR)/unittests_libknot.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/unittests_libknot.c' object='unittests_libknot.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_libknot.obj `if test -f 'tests/libknot/unittests_libknot.c'; then $(CYGPATH_W) 'tests/libknot/unittests_libknot.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/unittests_libknot.c'; fi`
+
+dname_tests_realdata.o: tests/libknot/realdata/libknot/dname_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_tests_realdata.o -MD -MP -MF $(DEPDIR)/dname_tests_realdata.Tpo -c -o dname_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/dname_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/dname_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_tests_realdata.Tpo $(DEPDIR)/dname_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/dname_tests_realdata.c' object='dname_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/dname_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/dname_tests_realdata.c
+
+dname_tests_realdata.obj: tests/libknot/realdata/libknot/dname_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dname_tests_realdata.obj -MD -MP -MF $(DEPDIR)/dname_tests_realdata.Tpo -c -o dname_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/dname_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/dname_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/dname_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dname_tests_realdata.Tpo $(DEPDIR)/dname_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/dname_tests_realdata.c' object='dname_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dname_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/dname_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/dname_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/dname_tests_realdata.c'; fi`
+
+response_tests_realdata.o: tests/libknot/realdata/libknot/response_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response_tests_realdata.o -MD -MP -MF $(DEPDIR)/response_tests_realdata.Tpo -c -o response_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/response_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/response_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response_tests_realdata.Tpo $(DEPDIR)/response_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/response_tests_realdata.c' object='response_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/response_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/response_tests_realdata.c
+
+response_tests_realdata.obj: tests/libknot/realdata/libknot/response_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT response_tests_realdata.obj -MD -MP -MF $(DEPDIR)/response_tests_realdata.Tpo -c -o response_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/response_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/response_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/response_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/response_tests_realdata.Tpo $(DEPDIR)/response_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/response_tests_realdata.c' object='response_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o response_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/response_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/response_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/response_tests_realdata.c'; fi`
+
+edns_tests_realdata.o: tests/libknot/realdata/libknot/edns_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns_tests_realdata.o -MD -MP -MF $(DEPDIR)/edns_tests_realdata.Tpo -c -o edns_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/edns_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/edns_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns_tests_realdata.Tpo $(DEPDIR)/edns_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/edns_tests_realdata.c' object='edns_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/edns_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/edns_tests_realdata.c
+
+edns_tests_realdata.obj: tests/libknot/realdata/libknot/edns_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT edns_tests_realdata.obj -MD -MP -MF $(DEPDIR)/edns_tests_realdata.Tpo -c -o edns_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/edns_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/edns_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/edns_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/edns_tests_realdata.Tpo $(DEPDIR)/edns_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/edns_tests_realdata.c' object='edns_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o edns_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/edns_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/edns_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/edns_tests_realdata.c'; fi`
+
+node_tests_realdata.o: tests/libknot/realdata/libknot/node_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node_tests_realdata.o -MD -MP -MF $(DEPDIR)/node_tests_realdata.Tpo -c -o node_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/node_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/node_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node_tests_realdata.Tpo $(DEPDIR)/node_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/node_tests_realdata.c' object='node_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/node_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/node_tests_realdata.c
+
+node_tests_realdata.obj: tests/libknot/realdata/libknot/node_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT node_tests_realdata.obj -MD -MP -MF $(DEPDIR)/node_tests_realdata.Tpo -c -o node_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/node_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/node_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/node_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/node_tests_realdata.Tpo $(DEPDIR)/node_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/node_tests_realdata.c' object='node_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o node_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/node_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/node_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/node_tests_realdata.c'; fi`
+
+rdata_tests_realdata.o: tests/libknot/realdata/libknot/rdata_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_tests_realdata.o -MD -MP -MF $(DEPDIR)/rdata_tests_realdata.Tpo -c -o rdata_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/rdata_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/rdata_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata_tests_realdata.Tpo $(DEPDIR)/rdata_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/rdata_tests_realdata.c' object='rdata_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/rdata_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/rdata_tests_realdata.c
+
+rdata_tests_realdata.obj: tests/libknot/realdata/libknot/rdata_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rdata_tests_realdata.obj -MD -MP -MF $(DEPDIR)/rdata_tests_realdata.Tpo -c -o rdata_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/rdata_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/rdata_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/rdata_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rdata_tests_realdata.Tpo $(DEPDIR)/rdata_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/rdata_tests_realdata.c' object='rdata_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rdata_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/rdata_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/rdata_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/rdata_tests_realdata.c'; fi`
+
+rrset_tests_realdata.o: tests/libknot/realdata/libknot/rrset_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset_tests_realdata.o -MD -MP -MF $(DEPDIR)/rrset_tests_realdata.Tpo -c -o rrset_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/rrset_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/rrset_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset_tests_realdata.Tpo $(DEPDIR)/rrset_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/rrset_tests_realdata.c' object='rrset_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/rrset_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/rrset_tests_realdata.c
+
+rrset_tests_realdata.obj: tests/libknot/realdata/libknot/rrset_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rrset_tests_realdata.obj -MD -MP -MF $(DEPDIR)/rrset_tests_realdata.Tpo -c -o rrset_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/rrset_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/rrset_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/rrset_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rrset_tests_realdata.Tpo $(DEPDIR)/rrset_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/rrset_tests_realdata.c' object='rrset_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rrset_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/rrset_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/rrset_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/rrset_tests_realdata.c'; fi`
+
+zone_tests_realdata.o: tests/libknot/realdata/libknot/zone_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tests_realdata.o -MD -MP -MF $(DEPDIR)/zone_tests_realdata.Tpo -c -o zone_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/zone_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/zone_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tests_realdata.Tpo $(DEPDIR)/zone_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/zone_tests_realdata.c' object='zone_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/zone_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/zone_tests_realdata.c
+
+zone_tests_realdata.obj: tests/libknot/realdata/libknot/zone_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone_tests_realdata.obj -MD -MP -MF $(DEPDIR)/zone_tests_realdata.Tpo -c -o zone_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/zone_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/zone_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/zone_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone_tests_realdata.Tpo $(DEPDIR)/zone_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/zone_tests_realdata.c' object='zone_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zone_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/zone_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/zone_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/zone_tests_realdata.c'; fi`
+
+zonedb_tests_realdata.o: tests/libknot/realdata/libknot/zonedb_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb_tests_realdata.o -MD -MP -MF $(DEPDIR)/zonedb_tests_realdata.Tpo -c -o zonedb_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/zonedb_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb_tests_realdata.Tpo $(DEPDIR)/zonedb_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/zonedb_tests_realdata.c' object='zonedb_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/zonedb_tests_realdata.c
+
+zonedb_tests_realdata.obj: tests/libknot/realdata/libknot/zonedb_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zonedb_tests_realdata.obj -MD -MP -MF $(DEPDIR)/zonedb_tests_realdata.Tpo -c -o zonedb_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zonedb_tests_realdata.Tpo $(DEPDIR)/zonedb_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/zonedb_tests_realdata.c' object='zonedb_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zonedb_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/zonedb_tests_realdata.c'; fi`
+
+packet_tests_realdata.o: tests/libknot/realdata/libknot/packet_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet_tests_realdata.o -MD -MP -MF $(DEPDIR)/packet_tests_realdata.Tpo -c -o packet_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/packet_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/packet_tests_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet_tests_realdata.Tpo $(DEPDIR)/packet_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/packet_tests_realdata.c' object='packet_tests_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet_tests_realdata.o `test -f 'tests/libknot/realdata/libknot/packet_tests_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot/packet_tests_realdata.c
+
+packet_tests_realdata.obj: tests/libknot/realdata/libknot/packet_tests_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet_tests_realdata.obj -MD -MP -MF $(DEPDIR)/packet_tests_realdata.Tpo -c -o packet_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/packet_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/packet_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/packet_tests_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet_tests_realdata.Tpo $(DEPDIR)/packet_tests_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot/packet_tests_realdata.c' object='packet_tests_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet_tests_realdata.obj `if test -f 'tests/libknot/realdata/libknot/packet_tests_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot/packet_tests_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot/packet_tests_realdata.c'; fi`
+
+libknot_tests_loader_realdata.o: tests/libknot/realdata/libknot_tests_loader_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot_tests_loader_realdata.o -MD -MP -MF $(DEPDIR)/libknot_tests_loader_realdata.Tpo -c -o libknot_tests_loader_realdata.o `test -f 'tests/libknot/realdata/libknot_tests_loader_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot_tests_loader_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libknot_tests_loader_realdata.Tpo $(DEPDIR)/libknot_tests_loader_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot_tests_loader_realdata.c' object='libknot_tests_loader_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot_tests_loader_realdata.o `test -f 'tests/libknot/realdata/libknot_tests_loader_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/libknot_tests_loader_realdata.c
+
+libknot_tests_loader_realdata.obj: tests/libknot/realdata/libknot_tests_loader_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libknot_tests_loader_realdata.obj -MD -MP -MF $(DEPDIR)/libknot_tests_loader_realdata.Tpo -c -o libknot_tests_loader_realdata.obj `if test -f 'tests/libknot/realdata/libknot_tests_loader_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot_tests_loader_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot_tests_loader_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libknot_tests_loader_realdata.Tpo $(DEPDIR)/libknot_tests_loader_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/libknot_tests_loader_realdata.c' object='libknot_tests_loader_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libknot_tests_loader_realdata.obj `if test -f 'tests/libknot/realdata/libknot_tests_loader_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/libknot_tests_loader_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/libknot_tests_loader_realdata.c'; fi`
+
+unittests_libknot_realdata.o: tests/libknot/realdata/unittests_libknot_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_libknot_realdata.o -MD -MP -MF $(DEPDIR)/unittests_libknot_realdata.Tpo -c -o unittests_libknot_realdata.o `test -f 'tests/libknot/realdata/unittests_libknot_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/unittests_libknot_realdata.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_libknot_realdata.Tpo $(DEPDIR)/unittests_libknot_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/unittests_libknot_realdata.c' object='unittests_libknot_realdata.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_libknot_realdata.o `test -f 'tests/libknot/realdata/unittests_libknot_realdata.c' || echo '$(srcdir)/'`tests/libknot/realdata/unittests_libknot_realdata.c
+
+unittests_libknot_realdata.obj: tests/libknot/realdata/unittests_libknot_realdata.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_libknot_realdata.obj -MD -MP -MF $(DEPDIR)/unittests_libknot_realdata.Tpo -c -o unittests_libknot_realdata.obj `if test -f 'tests/libknot/realdata/unittests_libknot_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/unittests_libknot_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/unittests_libknot_realdata.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_libknot_realdata.Tpo $(DEPDIR)/unittests_libknot_realdata.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/libknot/realdata/unittests_libknot_realdata.c' object='unittests_libknot_realdata.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_libknot_realdata.obj `if test -f 'tests/libknot/realdata/unittests_libknot_realdata.c'; then $(CYGPATH_W) 'tests/libknot/realdata/unittests_libknot_realdata.c'; else $(CYGPATH_W) '$(srcdir)/tests/libknot/realdata/unittests_libknot_realdata.c'; fi`
+
+unittests_zp_main.o: zcompile/tests/unittests_zp_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_zp_main.o -MD -MP -MF $(DEPDIR)/unittests_zp_main.Tpo -c -o unittests_zp_main.o `test -f 'zcompile/tests/unittests_zp_main.c' || echo '$(srcdir)/'`zcompile/tests/unittests_zp_main.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_zp_main.Tpo $(DEPDIR)/unittests_zp_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/tests/unittests_zp_main.c' object='unittests_zp_main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_zp_main.o `test -f 'zcompile/tests/unittests_zp_main.c' || echo '$(srcdir)/'`zcompile/tests/unittests_zp_main.c
+
+unittests_zp_main.obj: zcompile/tests/unittests_zp_main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unittests_zp_main.obj -MD -MP -MF $(DEPDIR)/unittests_zp_main.Tpo -c -o unittests_zp_main.obj `if test -f 'zcompile/tests/unittests_zp_main.c'; then $(CYGPATH_W) 'zcompile/tests/unittests_zp_main.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/tests/unittests_zp_main.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/unittests_zp_main.Tpo $(DEPDIR)/unittests_zp_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zcompile/tests/unittests_zp_main.c' object='unittests_zp_main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unittests_zp_main.obj `if test -f 'zcompile/tests/unittests_zp_main.c'; then $(CYGPATH_W) 'zcompile/tests/unittests_zp_main.c'; else $(CYGPATH_W) '$(srcdir)/zcompile/tests/unittests_zp_main.c'; fi`
+
+.l.c:
+ $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+libknotd_la-cf-lex.c: knot/conf/cf-lex.l
+ \
+ $(am__skiplex) \
+ $(SHELL) $(YLWRAP) `test -f 'knot/conf/cf-lex.l' || echo '$(srcdir)/'`knot/conf/cf-lex.l $(LEX_OUTPUT_ROOT).c libknotd_la-cf-lex.c -- $(LEX) $(LFLAGS) $(libknotd_la_LFLAGS)
+
+zlexer.c: zcompile/zlexer.l
+ \
+ $(am__skiplex) \
+ $(SHELL) $(YLWRAP) `test -f 'zcompile/zlexer.l' || echo '$(srcdir)/'`zcompile/zlexer.l $(LEX_OUTPUT_ROOT).c zlexer.c -- $(LEX) $(LFLAGS) $(AM_LFLAGS)
+
+.y.c:
+ $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE)
+
+libknotd_la-cf-parse.c: knot/conf/cf-parse.y
+ \
+ $(am__skipyacc) \
+ $(SHELL) $(YLWRAP) `test -f 'knot/conf/cf-parse.y' || echo '$(srcdir)/'`knot/conf/cf-parse.y y.tab.c libknotd_la-cf-parse.c y.tab.h libknotd_la-cf-parse.h y.output libknotd_la-cf-parse.output -- $(YACC) $(YFLAGS) $(libknotd_la_YFLAGS)
+
+zparser.c: zcompile/zparser.y
+ \
+ $(am__skipyacc) \
+ $(SHELL) $(YLWRAP) `test -f 'zcompile/zparser.y' || echo '$(srcdir)/'`zcompile/zparser.y y.tab.c zparser.c y.tab.h zparser.h y.output zparser.output -- $(YACC) $(YFLAGS) $(AM_YFLAGS)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man8: $(man8_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \
+ { for i in $$list; do echo "$$i"; done; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ test -z "$$files" || { \
+ echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(man8dir)" && rm -f $$files; }
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @list='$(MANS)'; if test -n "$$list"; then \
+ list=`for p in $$list; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+ if test -n "$$list" && \
+ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
+ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \
+ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+ echo " typically \`make maintainer-clean' will remove them" >&2; \
+ exit 1; \
+ else :; fi; \
+ else :; fi
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) config.h
+installdirs:
+ for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f libknotd_la-cf-lex.c
+ -rm -f libknotd_la-cf-parse.c
+ -rm -f libknotd_la-cf-parse.h
+ -rm -f zlexer.c
+ -rm -f zparser.c
+ -rm -f zparser.h
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \
+ clean-noinstLTLIBRARIES clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libexecPROGRAMS install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man8
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libexecPROGRAMS uninstall-man \
+ uninstall-sbinPROGRAMS
+
+uninstall-man: uninstall-man8
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libexecPROGRAMS clean-libtool clean-noinstLTLIBRARIES \
+ clean-sbinPROGRAMS ctags distclean distclean-compile \
+ distclean-generic distclean-hdr distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-libexecPROGRAMS install-man install-man8 install-pdf \
+ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-libexecPROGRAMS uninstall-man uninstall-man8 \
+ uninstall-sbinPROGRAMS
+
+
+# automake complains on % rules:
+# `%'-style pattern rules are a GNU make extension
+
+tests/libknot/parsed_data.rc: tests/libknot/files/parsed_data
+ ../resource.sh tests/libknot/files/parsed_data >$@
+
+tests/libknot/realdata/parsed_data.rc: tests/libknot/realdata/files/parsed_data
+ ../resource.sh tests/libknot/realdata/files/parsed_data >$@
+
+tests/libknot/parsed_data_queries.rc: tests/libknot/files/parsed_data_queries
+ ../resource.sh tests/libknot/files/parsed_data_queries >$@
+
+tests/libknot/raw_data_queries.rc: tests/libknot/files/raw_data_queries
+ ../resource.sh tests/libknot/files/raw_data_queries >$@
+
+tests/libknot/raw_data.rc: tests/libknot/files/raw_data
+ ../resource.sh tests/libknot/files/raw_data >$@
+
+tests/libknot/realdata/raw_data.rc: tests/libknot/realdata/files/raw_data
+ ../resource.sh tests/libknot/realdata/files/raw_data >$@
+
+tests/sample_conf.rc: tests/files/sample_conf
+ ../resource.sh tests/files/sample_conf >$@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/common/WELL1024a.c b/src/common/WELL1024a.c
new file mode 100644
index 0000000..dddf75e
--- /dev/null
+++ b/src/common/WELL1024a.c
@@ -0,0 +1,116 @@
+/* ***************************************************************************** */
+/* Copyright: Francois Panneton and Pierre L'Ecuyer, University of Montreal */
+/* Makoto Matsumoto, Hiroshima University */
+/* Notice: This code can be used freely for personal, academic, */
+/* or non-commercial purposes. For commercial purposes, */
+/* please contact P. L'Ecuyer at: lecuyer@iro.UMontreal.ca */
+/* ***************************************************************************** */
+
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdio.h>
+
+#include "WELL1024a.h"
+
+#define W 32
+#define M1 3
+#define M2 24
+#define M3 10
+
+#define MAT0POS(t,v) (v^(v>>t))
+#define MAT0NEG(t,v) (v^(v<<(-(t))))
+#define Identity(v) (v)
+
+#define V0(s) (s)->state[(s)->i ]
+#define VM1(s) (s)->state[((s)->i+M1) & 0x0000001fU]
+#define VM2(s) (s)->state[((s)->i+M2) & 0x0000001fU]
+#define VM3(s) (s)->state[((s)->i+M3) & 0x0000001fU]
+#define VRm1(s) (s)->state[((s)->i+31) & 0x0000001fU]
+#define newV0(s) (s)->state[((s)->i+31) & 0x0000001fU]
+#define newV1(s) (s)->state[(s)->i ]
+
+#define FACT 2.32830643653869628906e-10
+
+rngstate_t* InitWELLRNG1024a (unsigned *init) {
+
+ rngstate_t *s = malloc(sizeof(rngstate_t));
+ if (s == 0) {
+ return 0;
+ }
+
+ s->i = 0;
+ for (int j = 0; j < WELL1024_WIDTH; j++)
+ s->state[j] = init[j];
+ return s;
+}
+
+double WELLRNG1024a (rngstate_t* s) {
+ unsigned z0 = VRm1(s);
+ unsigned z1 = Identity(V0(s)) ^ MAT0POS (8, VM1(s));
+ unsigned z2 = MAT0NEG (-19, VM2(s)) ^ MAT0NEG(-14,VM3(s));
+ newV1(s) = z1 ^ z2;
+ newV0(s) = MAT0NEG (-11,z0) ^ MAT0NEG(-7,z1) ^ MAT0NEG(-13,z2) ;
+ s->i = (s->i + 31) & 0x0000001fU;
+ return ((double) s->state[s->i] * FACT);
+}
+
+/*! \brief TLS unique key for each thread seed. */
+static pthread_key_t tls_prng_key;
+static pthread_once_t tls_prng_once = PTHREAD_ONCE_INIT;
+
+static void tls_prng_deinit(void *ptr)
+{
+ free(ptr);
+}
+
+static void tls_prng_deinit_main()
+{
+ tls_prng_deinit(pthread_getspecific(tls_prng_key));
+}
+
+static void tls_prng_init()
+{
+ (void) pthread_key_create(&tls_prng_key, tls_prng_deinit);
+ atexit(tls_prng_deinit_main); // Main thread cleanup
+}
+
+double tls_rand()
+{
+ /* Setup PRNG state for current thread. */
+ (void)pthread_once(&tls_prng_once, tls_prng_init);
+
+ /* Create PRNG state if not exists. */
+ rngstate_t* s = pthread_getspecific(tls_prng_key);
+ if (!s) {
+ /* Initialize seed from system PRNG generator. */
+ unsigned init[WELL1024_WIDTH];
+ FILE *fp = fopen("/dev/urandom", "r");
+ for (unsigned i = 0; i < WELL1024_WIDTH; ++i) {
+ int rc = fread(&init[i], sizeof(unsigned), 1, fp);
+ rc = rc;
+ }
+ fclose(fp);
+
+ /* Initialize PRNG state. */
+ s = InitWELLRNG1024a(init);
+ (void)pthread_setspecific(tls_prng_key, s);
+ }
+
+ return WELLRNG1024a(s);
+}
+
+void tls_seed_set(unsigned init[WELL1024_WIDTH])
+{
+ /* Initialize new PRNG state if not exists. */
+ rngstate_t* s = pthread_getspecific(tls_prng_key);
+ if (!s) {
+ s = InitWELLRNG1024a(init);
+ (void)pthread_setspecific(tls_prng_key, s);
+ } else {
+ /* Reset PRNG state if exists. */
+ memcpy(s->state, init, sizeof(unsigned) * WELL1024_WIDTH);
+ s->i = 0;
+ }
+}
diff --git a/src/common/WELL1024a.h b/src/common/WELL1024a.h
new file mode 100644
index 0000000..04bf1a1
--- /dev/null
+++ b/src/common/WELL1024a.h
@@ -0,0 +1,32 @@
+/* ***************************************************************************** */
+/* Copyright: Francois Panneton and Pierre L'Ecuyer, University of Montreal */
+/* Makoto Matsumoto, Hiroshima University */
+/* Notice: This code can be used freely for personal, academic, */
+/* or non-commercial purposes. For commercial purposes, */
+/* please contact P. L'Ecuyer at: lecuyer@iro.UMontreal.ca */
+/* ***************************************************************************** */
+
+#define WELL1024_WIDTH 32 /* 128 bytes */
+
+typedef struct {
+ unsigned i;
+ unsigned state[WELL1024_WIDTH];
+} rngstate_t;
+
+rngstate_t* InitWELLRNG1024a (unsigned *init);
+double WELLRNG1024a (rngstate_t* s);
+
+/*!
+ * \brief Get pseudorandom number from PRNG initialized in thread-local storage.
+ *
+ * No need for initialization, TLS will take care of it.
+ *
+ * \retval Pseudorandom number.
+ */
+double tls_rand();
+
+/*!
+ * \brief Set PRNG seed in thread-local storage to requested value.
+ *
+ */
+void tls_seed_set(unsigned init[WELL1024_WIDTH]);
diff --git a/src/common/acl.c b/src/common/acl.c
new file mode 100644
index 0000000..e73c4dd
--- /dev/null
+++ b/src/common/acl.c
@@ -0,0 +1,185 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "common/acl.h"
+
+static int acl_compare(void *k1, void *k2)
+{
+ sockaddr_t* a1 = (sockaddr_t *)k1;
+ sockaddr_t* a2 = (sockaddr_t *)k2;
+
+ /* Check different length, IPv4 goes first. */
+ int ldiff = a1->len - a2->len;
+ if (ldiff != 0) {
+ return ldiff < 0 ? -1 : 1;
+ }
+
+ /* Compare integers if IPv4. */
+ if (a1->len == sizeof(struct sockaddr_in)) {
+
+ /* Allow if k1 == INADDR_ANY. */
+ if (a1->addr4.sin_addr.s_addr == 0) {
+ return 0;
+ }
+
+ /* Compare address. */
+ ldiff = a1->addr4.sin_addr.s_addr - a2->addr4.sin_addr.s_addr;
+ if (ldiff != 0) {
+ return ldiff < 0 ? -1 : 1;
+ }
+
+ /* Port = 0 means any port match. */
+ if (a1->addr4.sin_port == 0) {
+ return 0;
+ }
+
+ /* Compare ports on address match. */
+ ldiff = ntohs(a1->addr4.sin_port) - ntohs(a2->addr4.sin_port);
+ if (ldiff != 0) {
+ return ldiff < 0 ? -1 : 1;
+ }
+ return 0;
+ }
+
+ /* IPv6 matching. */
+#ifndef DISABLE_IPV6
+ if (a1->len == sizeof(struct sockaddr_in6)) {
+
+ /* Compare address. */
+ /*! \todo Maybe use memcmp()? */
+ ldiff = 0;
+ const unsigned int *a6 = (const unsigned int *)&a1->addr6.sin6_addr;
+ const unsigned int *b6 = (const unsigned int *)&a2->addr6.sin6_addr;
+ for (int i = 0; i < (sizeof(struct in6_addr)/ sizeof(int)) ; ++i) {
+ ldiff = a6[i] - b6[i];
+ if (ldiff < 0) {
+ return -1;
+ }
+ if (ldiff > 0) {
+ return 1;
+ }
+ }
+
+ /* Port = 0 means any port match. */
+ if (a1->addr6.sin6_port == 0) {
+ return 0;
+ }
+
+ /* Compare ports on address match. */
+ ldiff = ntohs(a1->addr6.sin6_port) - ntohs(a2->addr6.sin6_port);
+ if (ldiff != 0) {
+ return ldiff < 0 ? -1 : 1;
+ }
+ return 0;
+ }
+#endif
+
+ return 0;
+}
+
+acl_t *acl_new(acl_rule_t default_rule, const char *name)
+{
+ /* Trailing '\0' for NULL name. */
+ size_t name_len = 1;
+ if (name) {
+ name_len += strlen(name);
+ } else {
+ name = "";
+ }
+
+ /* Allocate memory for ACL. */
+ acl_t* acl = malloc(sizeof(acl_t) + name_len);
+ if (!acl) {
+ return 0;
+ }
+
+ /* Initialize skip list. */
+ acl->rules = skip_create_list(acl_compare);
+ if (!acl->rules) {
+ free(acl);
+ return 0;
+ }
+
+ /* Initialize. */
+ memcpy(&acl->name, name, name_len);
+ acl->default_rule = default_rule;
+ return acl;
+}
+
+void acl_delete(acl_t **acl)
+{
+ if ((acl == NULL) || (*acl == NULL)) {
+ return;
+ }
+
+ /* Truncate rules. */
+ if (acl_truncate(*acl) != ACL_ACCEPT) {
+ return;
+ }
+
+ /* Free ACL. */
+ free(*acl);
+ *acl = 0;
+}
+
+int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule)
+{
+ if (!acl || !addr || rule < 0) {
+ return ACL_ERROR;
+ }
+
+ /* Insert into skip list. */
+ sockaddr_t *key = malloc(sizeof(sockaddr_t));
+ memcpy(key, addr, sizeof(sockaddr_t));
+
+ skip_insert(acl->rules, key, (void*)((ssize_t)rule + 1), 0);
+
+ return ACL_ACCEPT;
+}
+
+int acl_match(acl_t *acl, sockaddr_t* addr)
+{
+ if (!acl || !addr) {
+ return ACL_ERROR;
+ }
+
+ /* Return default rule if not found.
+ * Conversion to the same length integer is made,
+ * but we can be sure, that the value range is within <-1,1>.
+ */
+ ssize_t val = ((ssize_t)skip_find(acl->rules, addr)) - 1;
+ if (val < 0) {
+ return acl->default_rule;
+ }
+
+ /* Return stored rule if found. */
+ return (int)val;
+}
+
+int acl_truncate(acl_t *acl)
+{
+ if (acl == NULL) {
+ return ACL_ERROR;
+ }
+
+ /* Destroy all rules. */
+ skip_destroy_list(&acl->rules, free, 0);
+
+ return ACL_ACCEPT;
+}
diff --git a/src/common/acl.h b/src/common/acl.h
new file mode 100644
index 0000000..c79db7f
--- /dev/null
+++ b/src/common/acl.h
@@ -0,0 +1,138 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file acl.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Access control lists.
+ *
+ * An access control list is a named structure
+ * for efficient IP address and port matching.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_ACL_H_
+#define _KNOTD_ACL_H_
+
+#include "common/skip-list.h"
+#include "common/sockaddr.h"
+
+/*! \brief ACL rules types. */
+typedef enum acl_rule_t {
+ ACL_ERROR = -1,
+ ACL_DENY = 0,
+ ACL_ACCEPT = 1
+} acl_rule_t;
+
+/*! \brief ACL structure. */
+typedef struct acl_t {
+ acl_rule_t default_rule;
+ skip_list_t *rules;
+ const char name[];
+} acl_t;
+
+/*!
+ * \brief Create a new ACL.
+ *
+ * \param default_rule Default rule for address matching.
+ * \param name ACL symbolic name (or NULL).
+ *
+ * \retval New ACL instance when successful.
+ * \retval NULL on errors.
+ */
+acl_t *acl_new(acl_rule_t default_rule, const char *name);
+
+/*!
+ * \brief Delete ACL structure.
+ *
+ * \param acl Pointer to ACL instance.
+ */
+void acl_delete(acl_t **acl);
+
+/*!
+ * \brief Create new ACL rule.
+ *
+ * \todo Support address subnets.
+ *
+ * \param acl Pointer to ACL instance.
+ * \param addr IP address (will be duplicated).
+ * \param rule Rule.
+ *
+ * \retval ACL_ACCEPT if successful.
+ * \retval ACP_ERROR on error.
+ */
+int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule);
+
+/*!
+ * \brief Match address against ACL.
+ *
+ * \param acl Pointer to ACL instance.
+ * \param addr IP address.
+ *
+ * \retval ACL_ACCEPT if the address is accepted.
+ * \retval ACL_DENY if the address is not accepted.
+ * \retval ACP_ERROR on error.
+ */
+int acl_match(acl_t *acl, sockaddr_t* addr);
+
+/*!
+ * \brief Truncate ACL.
+ *
+ * All but the default rule will be dropped.
+ *
+ * \param acl Pointer to ACL instance.
+ *
+ * \retval ACL_ACCEPT if successful.
+ * \retval ACP_ERROR on error.
+ */
+int acl_truncate(acl_t *acl);
+
+/*!
+ * \brief Return ACL name.
+ *
+ * \param acl Pointer to ACL instance.
+ *
+ * \retval ACL name.
+ */
+static inline const char* acl_name(acl_t *acl) {
+ if (!acl) {
+ return 0;
+ }
+
+ return acl->name;
+}
+
+/*!
+ * \brief Return ACL rules.
+ *
+ * \param acl Pointer to ACL instance.
+ *
+ * \retval ACL rules skip-list.
+ */
+static inline skip_list_t* acl_rules(acl_t *acl) {
+ if (!acl) {
+ return 0;
+ }
+
+ return acl->rules;
+}
+
+#endif /* _KNOTD_ACL_H_ */
+
+/*! @} */
diff --git a/src/common/base32.c b/src/common/base32.c
new file mode 100644
index 0000000..43b86c1
--- /dev/null
+++ b/src/common/base32.c
@@ -0,0 +1,539 @@
+/* base32.c -- Encode binary data using printable characters.
+ Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006, 2010 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Adapted from base64.{h,c} by Ondřej Surý. base64.{h,c} was written
+ * by Simon Josefsson. Partially adapted from GNU MailUtils
+ * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
+ * from Paul Eggert, Bruno Haible, and Stepan Kasal.
+ *
+ * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
+ *
+ * Be careful with error checking. Here is how you would typically
+ * use these functions:
+ *
+ * bool ok = base32_decode_alloc (in, inlen, &out, &outlen);
+ * if (!ok)
+ * FAIL: input was not valid base32
+ * if (out == NULL)
+ * FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN
+ *
+ * size_t outlen = base32_encode_alloc (in, inlen, &out);
+ * if (out == NULL && outlen == 0 && inlen != 0)
+ * FAIL: input too long
+ * if (out == NULL)
+ * FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN.
+ *
+ */
+
+/* Get prototype. */
+#include "base32.h"
+
+/* Get malloc. */
+#include <stdlib.h>
+
+/* Get UCHAR_MAX. */
+#include <limits.h>
+
+/* C89 compliant way to cast 'char' to 'unsigned char'. */
+static inline unsigned char to_uchar(char ch)
+{
+ return ch;
+}
+
+/* Base32 encode IN array of size INLEN into OUT array of size OUTLEN.
+ If OUTLEN is less than BASE32_LENGTH(INLEN), write as many bytes as
+ possible. If OUTLEN is larger than BASE32_LENGTH(INLEN), also zero
+ terminate the output buffer. */
+void base32_encode(const char *in, size_t inlen, char *out, size_t outlen)
+{
+ static const char b32str[32] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+ while (inlen && outlen) {
+ *out++ = b32str[(to_uchar(in[0]) >> 3) & 0x1f];
+ if (!--outlen) {
+ break;
+ }
+ *out++ = b32str[((to_uchar(in[0]) << 2)
+ + (--inlen ? to_uchar(in[1]) >> 6 : 0))
+ & 0x1f];
+ if (!--outlen) {
+ break;
+ }
+ *out++ =(inlen
+ ? b32str[(to_uchar(in[1]) >> 1) & 0x1f]
+ : '=');
+ if (!--outlen) {
+ break;
+ }
+ *out++ = (inlen
+ ? b32str[((to_uchar(in[1]) << 4)
+ + (--inlen ? to_uchar(in[2]) >> 4 : 0))
+ & 0x1f]
+ : '=');
+ if (!--outlen) {
+ break;
+ }
+ *out++ = (inlen
+ ? b32str[((to_uchar(in[2]) << 1)
+ + (--inlen ? to_uchar(in[3]) >> 7 : 0))
+ & 0x1f]
+ : '=');
+ if (!--outlen) {
+ break;
+ }
+ *out++ = (inlen
+ ? b32str[(to_uchar(in[3]) >> 2) & 0x1f]
+ : '=');
+ if (!--outlen)
+ {
+ break;
+ }
+ *out++ = (inlen
+ ? b32str[((to_uchar(in[3]) << 3)
+ + (--inlen ? to_uchar(in[4]) >> 5 : 0))
+ & 0x1f]
+ : '=');
+ if (!--outlen) {
+ break;
+ }
+ *out++ = inlen ? b32str[to_uchar(in[4]) & 0x1f] : '=';
+ if (!--outlen) {
+ break;
+ }
+ if (inlen) {
+ inlen--;
+ }
+ if (inlen) {
+ in += 5;
+ }
+ }
+
+ if (outlen) {
+ *out = '\0';
+ }
+}
+
+/* Allocate a buffer and store zero terminated base32 encoded data
+ from array IN of size INLEN, returning BASE32_LENGTH(INLEN), i.e.,
+ the length of the encoded data, excluding the terminating zero. On
+ return, the OUT variable will hold a pointer to newly allocated
+ memory that must be deallocated by the caller. If output string
+ length would overflow, 0 is returned and OUT is set to NULL. If
+ memory allocation failed, OUT is set to NULL, and the return value
+ indicates length of the requested memory block, i.e.,
+ BASE32_LENGTH(inlen) + 1. */
+size_t base32_encode_alloc(const char *in, size_t inlen, char **out)
+{
+ size_t outlen = 1 + BASE32_LENGTH (inlen);
+
+ /* Check for overflow in outlen computation.
+ *
+ * If there is no overflow, outlen >= inlen.
+ *
+ * If the operation (inlen + 2) overflows then it yields at most +1, so
+ * outlen is 0.
+ *
+ * If the multiplication overflows, we lose at least half of the
+ * correct value, so the result is < ((inlen + 2) / 3) * 2, which is
+ * less than (inlen + 2) * 0.66667, which is less than inlen as soon as
+ * (inlen > 4).
+ */
+ if (inlen > outlen)
+ {
+ *out = NULL;
+ return 0;
+ }
+
+ *out = malloc(outlen);
+ if (!*out) {
+ return outlen;
+ }
+
+ base32_encode(in, inlen, *out, outlen);
+
+ return outlen - 1;
+}
+
+/* With this approach this file works independent of the charset used
+ (think EBCDIC). However, it does assume that the characters in the
+ Base32 alphabet (A-Z2-7) are encoded in 0..255. POSIX
+ 1003.1-2001 require that char and unsigned char are 8-bit
+ quantities, though, taking care of that problem. But this may be a
+ potential problem on non-POSIX C99 platforms.
+
+ IBM C V6 for AIX mishandles "#define B32(x) ...'x'...", so use "_"
+ as the formal parameter rather than "x". */
+#define B32(_) \
+ ((_) == 'A' ? 0 \
+ : (_) == 'B' ? 1 \
+ : (_) == 'C' ? 2 \
+ : (_) == 'D' ? 3 \
+ : (_) == 'E' ? 4 \
+ : (_) == 'F' ? 5 \
+ : (_) == 'G' ? 6 \
+ : (_) == 'H' ? 7 \
+ : (_) == 'I' ? 8 \
+ : (_) == 'J' ? 9 \
+ : (_) == 'K' ? 10 \
+ : (_) == 'L' ? 11 \
+ : (_) == 'M' ? 12 \
+ : (_) == 'N' ? 13 \
+ : (_) == 'O' ? 14 \
+ : (_) == 'P' ? 15 \
+ : (_) == 'Q' ? 16 \
+ : (_) == 'R' ? 17 \
+ : (_) == 'S' ? 18 \
+ : (_) == 'T' ? 19 \
+ : (_) == 'U' ? 20 \
+ : (_) == 'V' ? 21 \
+ : (_) == 'W' ? 22 \
+ : (_) == 'X' ? 23 \
+ : (_) == 'Y' ? 24 \
+ : (_) == 'Z' ? 25 \
+ : (_) == '2' ? 26 \
+ : (_) == '3' ? 27 \
+ : (_) == '4' ? 28 \
+ : (_) == '5' ? 29 \
+ : (_) == '6' ? 30 \
+ : (_) == '7' ? 31 \
+ : -1)
+
+static const signed char b32[0x100] = {
+ B32 (0), B32 (1), B32 (2), B32 (3),
+ B32 (4), B32 (5), B32 (6), B32 (7),
+ B32 (8), B32 (9), B32 (10), B32 (11),
+ B32 (12), B32 (13), B32 (14), B32 (15),
+ B32 (16), B32 (17), B32 (18), B32 (19),
+ B32 (20), B32 (21), B32 (22), B32 (23),
+ B32 (24), B32 (25), B32 (26), B32 (27),
+ B32 (28), B32 (29), B32 (30), B32 (31),
+ B32 (32), B32 (33), B32 (34), B32 (35),
+ B32 (36), B32 (37), B32 (38), B32 (39),
+ B32 (40), B32 (41), B32 (42), B32 (43),
+ B32 (44), B32 (45), B32 (46), B32 (47),
+ B32 (48), B32 (49), B32 (50), B32 (51),
+ B32 (52), B32 (53), B32 (54), B32 (55),
+ B32 (56), B32 (57), B32 (58), B32 (59),
+ B32 (60), B32 (61), B32 (62), B32 (63),
+ B32 (64), B32 (65), B32 (66), B32 (67),
+ B32 (68), B32 (69), B32 (70), B32 (71),
+ B32 (72), B32 (73), B32 (74), B32 (75),
+ B32 (76), B32 (77), B32 (78), B32 (79),
+ B32 (80), B32 (81), B32 (82), B32 (83),
+ B32 (84), B32 (85), B32 (86), B32 (87),
+ B32 (88), B32 (89), B32 (90), B32 (91),
+ B32 (92), B32 (93), B32 (94), B32 (95),
+ B32 (96), B32 (97), B32 (98), B32 (99),
+ B32 (100), B32 (101), B32 (102), B32 (103),
+ B32 (104), B32 (105), B32 (106), B32 (107),
+ B32 (108), B32 (109), B32 (110), B32 (111),
+ B32 (112), B32 (113), B32 (114), B32 (115),
+ B32 (116), B32 (117), B32 (118), B32 (119),
+ B32 (120), B32 (121), B32 (122), B32 (123),
+ B32 (124), B32 (125), B32 (126), B32 (127),
+ B32 (128), B32 (129), B32 (130), B32 (131),
+ B32 (132), B32 (133), B32 (134), B32 (135),
+ B32 (136), B32 (137), B32 (138), B32 (139),
+ B32 (140), B32 (141), B32 (142), B32 (143),
+ B32 (144), B32 (145), B32 (146), B32 (147),
+ B32 (148), B32 (149), B32 (150), B32 (151),
+ B32 (152), B32 (153), B32 (154), B32 (155),
+ B32 (156), B32 (157), B32 (158), B32 (159),
+ B32 (160), B32 (161), B32 (162), B32 (163),
+ B32 (164), B32 (165), B32 (166), B32 (167),
+ B32 (168), B32 (169), B32 (170), B32 (171),
+ B32 (172), B32 (173), B32 (174), B32 (175),
+ B32 (176), B32 (177), B32 (178), B32 (179),
+ B32 (180), B32 (181), B32 (182), B32 (183),
+ B32 (184), B32 (185), B32 (186), B32 (187),
+ B32 (188), B32 (189), B32 (190), B32 (191),
+ B32 (192), B32 (193), B32 (194), B32 (195),
+ B32 (196), B32 (197), B32 (198), B32 (199),
+ B32 (200), B32 (201), B32 (202), B32 (203),
+ B32 (204), B32 (205), B32 (206), B32 (207),
+ B32 (208), B32 (209), B32 (210), B32 (211),
+ B32 (212), B32 (213), B32 (214), B32 (215),
+ B32 (216), B32 (217), B32 (218), B32 (219),
+ B32 (220), B32 (221), B32 (222), B32 (223),
+ B32 (224), B32 (225), B32 (226), B32 (227),
+ B32 (228), B32 (229), B32 (230), B32 (231),
+ B32 (232), B32 (233), B32 (234), B32 (235),
+ B32 (236), B32 (237), B32 (238), B32 (239),
+ B32 (240), B32 (241), B32 (242), B32 (243),
+ B32 (244), B32 (245), B32 (246), B32 (247),
+ B32 (248), B32 (249), B32 (250), B32 (251),
+ B32 (252), B32 (253), B32 (254), B32 (255)
+};
+
+#if UCHAR_MAX == 255
+#define uchar_in_range(c) true
+#else
+#define uchar_in_range(c) ((c) <= 255)
+#endif
+
+/* Return true if CH is a character from the Base32 alphabet, and
+ false otherwise. Note that '=' is padding and not considered to be
+ part of the alphabet. */
+bool isbase32(char ch)
+{
+ return uchar_in_range(to_uchar(ch)) && 0 <= b32[to_uchar(ch)];
+}
+
+/* Decode base32 encoded input array IN of length INLEN to output
+ array OUT that can hold *OUTLEN bytes. Return true if decoding was
+ successful, i.e. if the input was valid base32 data, false
+ otherwise. If *OUTLEN is too small, as many bytes as possible will
+ be written to OUT. On return, *OUTLEN holds the length of decoded
+ bytes in OUT. Note that as soon as any non-alphabet characters are
+ encountered, decoding is stopped and false is returned. This means
+ that, when applicable, you must remove any line terminators that is
+ part of the data stream before calling this function. */
+bool base32_decode(const char *in, size_t inlen, char *out, size_t *outlen)
+{
+ size_t outleft = *outlen;
+
+ while (inlen >= 2) {
+ if (!isbase32(in[0]) || !isbase32(in[1])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ = ((b32[to_uchar(in[0])] << 3)
+ | (b32[to_uchar(in[1])] >> 2));
+ outleft--;
+ }
+
+ if (inlen == 2) {
+ break;
+ }
+
+ if (in[2] == '=') {
+ if (inlen != 8) {
+ break;
+ }
+
+ if ((in[3] != '=') ||
+ (in[4] != '=') ||
+ (in[5] != '=') ||
+ (in[6] != '=') ||
+ (in[7] != '=')) {
+ break;
+ }
+ } else {
+ if (!isbase32(in[2]) || !isbase32(in[3])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ = ((b32[to_uchar(in[1])] << 6)
+ | ((b32[to_uchar(in[2])] << 1) & 0x3E)
+ | (b32[to_uchar(in[3])] >> 4));
+ outleft--;
+ }
+
+ if (inlen == 4) {
+ break;
+ }
+
+ if (in[4] == '=') {
+ if (inlen != 8) {
+ break;
+ }
+
+ if ((in[5] != '=') ||
+ (in[6] != '=') ||
+ (in[7] != '=')) {
+ break;
+ }
+ } else {
+ if (!isbase32 (in[3]) || !isbase32(in[4])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ = ((b32[to_uchar(in[3])] << 4)
+ | (b32[to_uchar(in[4])] >> 1));
+ outleft--;
+ }
+
+ if (inlen == 5) {
+ break;
+ }
+
+ if (in[5] == '=') {
+ if (inlen != 8) {
+ break;
+ }
+
+ if ((in[6] != '=')
+ || (in[7] != '=')) {
+ break;
+ }
+ } else {
+ if (!isbase32 (in[5])
+ || !isbase32 (in[6])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ = ((b32[to_uchar(in[4])]
+ << 7)
+ | (b32[to_uchar(in[5])] << 2)
+ | (b32[to_uchar(in[6])]
+ >> 3));
+ outleft--;
+ }
+
+ if (inlen == 7) {
+ break;
+ }
+
+ if (in[7] == '=') {
+ if (inlen != 8) {
+ break;
+ }
+ } else {
+ if (!isbase32 (in[7])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ =
+ ((b32[to_uchar(in[6])]
+ << 5) | (b32[
+ to_uchar(in[7])]));
+ outleft--;
+ }
+ }
+ }
+ }
+ }
+
+ in += 8;
+ inlen -= 8;
+ }
+
+ *outlen -= outleft;
+
+ if (inlen != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Allocate an output buffer in *OUT, and decode the base32 encoded
+ data stored in IN of size INLEN to the *OUT buffer. On return, the
+ size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
+ if the caller is not interested in the decoded length. *OUT may be
+ NULL to indicate an out of memory error, in which case *OUTLEN
+ contains the size of the memory block needed. The function returns
+ true on successful decoding and memory allocation errors. (Use the
+ *OUT and *OUTLEN parameters to differentiate between successful
+ decoding and memory error.) The function returns false if the
+ input was invalid, in which case *OUT is NULL and *OUTLEN is
+ undefined. */
+bool base32_decode_alloc(const char *in, size_t inlen, char **out,
+ size_t *outlen)
+{
+ /* This may allocate a few bytes too much, depending on input,
+ but it's not worth the extra CPU time to compute the exact amount.
+ The exact amount is 5 * inlen / 8, minus 1 if the input ends
+ with "=" and minus another 1 if the input ends with "==", etc.
+ Dividing before multiplying avoids the possibility of overflow. */
+ size_t needlen = 5 * (inlen / 8) + 4;
+
+ *out = malloc(needlen);
+ if (!*out) {
+ return true;
+ }
+
+ if (!base32_decode(in, inlen, *out, &needlen)) {
+ free (*out);
+ *out = NULL;
+ return false;
+ }
+
+ if (outlen) {
+ *outlen = needlen;
+ }
+
+ return true;
+}
+
+#ifdef MAIN
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include "base32.h"
+
+int main(int argc, char **argv) {
+ int i = 1;
+ size_t inlen, outlen, argvlen;
+ char *out;
+ char *in;
+ bool ok;
+
+ while (argc > 1) {
+ argv++; argc--;
+ argvlen = strlen(*argv);
+
+ outlen = base32_encode_alloc(*argv, argvlen, &out);
+
+ if (out == NULL && outlen == 0 && inlen != 0) {
+ fprintf(stderr, "ERROR(encode): input too long: %zd\n",
+ outlen);
+ return 1;
+ }
+
+ if (out == NULL) {
+ fprintf(stderr, "ERROR(encode): memory allocation error"
+ "\n");
+ return 1;
+ }
+
+ ok = base32_decode_alloc(out, outlen, &in, &inlen);
+
+ if (!ok) {
+ fprintf(stderr, "ERROR(decode): input was not valid "
+ "base32: `%s'\n", out);
+ return 1;
+ }
+
+ if (in == NULL) {
+ fprintf(stderr, "ERROR(decode): memory allocation "
+ "error\n");
+ }
+
+ if ((inlen != argvlen) ||
+ strcmp(*argv, in) != 0) {
+ fprintf(stderr, "ERROR(encode/decode): input `%s' and "
+ "output `%s'\n", *argv, in);
+ return 1;
+ }
+ printf("INPUT: `%s'\nENCODE: `%s'\nDECODE: `%s'\n", *argv, out,
+ in);
+ }
+}
+
+#endif
diff --git a/src/common/base32.h b/src/common/base32.h
new file mode 100644
index 0000000..45df9fa
--- /dev/null
+++ b/src/common/base32.h
@@ -0,0 +1,121 @@
+/* base32.h -- Encode binary data using printable characters.
+ Copyright (C) 2004, 2005, 2006, 2010 Free Software Foundation, Inc.
+ Written by Ondřej Surý & Simon Josefsson.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _BASE32_H_
+#define _BASE32_H_
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get bool. */
+#include <stdbool.h>
+
+/*!
+ * \brief Counts the size of the Base32-encoded output for given input length.
+ *
+ * \note This uses that the expression (n+(k-1))/k means the smallest
+ * integer >= n/k, i.e., the ceiling of n/k.
+ */
+#define BASE32_LENGTH(inlen) ((((inlen) + 4) / 5) * 8)
+
+/*!
+ * \brief Checks if the given character belongs to the Base32 alphabet.
+ *
+ * \param ch Character to check.
+ *
+ * \retval true if \a ch belongs to the Base32 alphabet.
+ * \retval false otherwise.
+ */
+extern bool isbase32(char ch);
+
+/*!
+ * \brief Encodes the given character array using Base32 encoding.
+ *
+ * If \a outlen is less than BASE32_LENGTH(\a inlen), the function writes as
+ * many bytes as possible to the output buffer. If \a outlen is more than
+ * BASE32_LENGTH(\a inlen), the output will be zero-terminated.
+ *
+ * \param in Input array of characters.
+ * \param inlen Length of the input array.
+ * \param out Output buffer.
+ * \param outlen Size of the output buffer.
+ */
+extern void base32_encode(const char *in, size_t inlen, char *out,
+ size_t outlen);
+
+/*!
+ * \brief Encodes the given character array using Base32 encoding and allocates
+ * space for the output.
+ *
+ * \param in Input array of characters.
+ * \param inlen Length of the input array.
+ * \param out Output buffer.
+ *
+ * \return Size of the allocated output buffer (0 if failed).
+ */
+extern size_t base32_encode_alloc(const char *in, size_t inlen, char **out);
+
+/*!
+ * \brief Decodes the given character array in Base32 encoding.
+ *
+ * If \a *outlen is too small, as many bytes as possible will be written to
+ * \a out. On return, \a *outlen holds the length of decoded bytes in \a out.
+ *
+ * \note As soon as any non-alphabet characters are encountered, decoding is
+ * stopped and false is returned. This means that, when applicable, you
+ * must remove any line terminators that is part of the data stream before
+ * calling this function.
+ *
+ * \param in Input array of characters.
+ * \param inlen Length of the input array.
+ * \param out Output buffer.
+ * \param outlen Size of the output buffer.
+ *
+ * \retval true if decoding was successful, i.e. if the input was valid base32
+ * data.
+ * \retval false otherwise.
+ */
+extern bool base32_decode(const char *in, size_t inlen, char *out,
+ size_t *outlen);
+
+/*!
+ * \brief Allocate an output buffer and decode the base32 encoded data to it.
+ *
+ * On return, the size of the decoded data is stored in \a *outlen. \a outlen
+ * may be NULL, if the caller is not interested in the decoded length. \a *out
+ * may be NULL to indicate an out of memory error, in which case \a *outlen
+ * contains the size of the memory block needed.
+ *
+ * \param in Input array of characters.
+ * \param inlen Length of the input array.
+ * \param out Output buffer. \a *out may be NULL to indicate an out of memory
+ * error in which case \a *outlen contains the size of the memory
+ * block needed
+ * \param outlen Size of the output buffer. May be NULL, if the caller is not
+ * interested in the decoded length
+ *
+ * \retval true on successful decoding and memory allocation errors. (Use the
+ * \a *out and \a *outlen parameters to differentiate between
+ * successful decoding and memory error.)
+ * \retval false if the input was invalid, in which case \a *out is NULL and
+ * \a *outlen is undefined.
+ */
+extern bool base32_decode_alloc(const char *in, size_t inlen, char **out,
+ size_t *outlen);
+
+#endif /* _BASE32_H_ */
diff --git a/src/common/base32hex.c b/src/common/base32hex.c
new file mode 100644
index 0000000..cd2d2ce
--- /dev/null
+++ b/src/common/base32hex.c
@@ -0,0 +1,562 @@
+/* base32hex.c -- Encode binary data using printable characters.
+ Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006, 2010 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Adapted from base32.{h,c}. base32.{h,c} was adapted from
+ * base64.{h,c} by Ondřej Surý. base64.{h,c} was written by Simon
+ * Josefsson. Partially adapted from GNU MailUtils
+ * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
+ * from Paul Eggert, Bruno Haible, and Stepan Kasal.
+ *
+ * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
+ *
+ * Be careful with error checking. Here is how you would typically
+ * use these functions:
+ *
+ * bool ok = base32hex_decode_alloc (in, inlen, &out, &outlen);
+ * if (!ok)
+ * FAIL: input was not valid base32hex
+ * if (out == NULL)
+ * FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN
+ *
+ * size_t outlen = base32hex_encode_alloc (in, inlen, &out);
+ * if (out == NULL && outlen == 0 && inlen != 0)
+ * FAIL: input too long
+ * if (out == NULL)
+ * FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN.
+ *
+ */
+
+/* Get prototype. */
+#include "base32hex.h"
+
+/* Get malloc. */
+#include <stdlib.h>
+
+/* Get UCHAR_MAX. */
+#include <limits.h>
+
+/* C89 compliant way to cast 'char' to 'unsigned char'. */
+static inline unsigned char to_uchar(char ch)
+{
+ return ch;
+}
+
+/* Base32hex encode IN array of size INLEN into OUT array of size OUTLEN.
+ If OUTLEN is less than BASE32HEX_LENGTH(INLEN), write as many bytes as
+ possible. If OUTLEN is larger than BASE32HEX_LENGTH(INLEN), also zero
+ terminate the output buffer. */
+void base32hex_encode(const char *in, size_t inlen, char *out, size_t outlen)
+{
+ static const char b32str[32] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+
+ while (inlen && outlen) {
+ *out++ = b32str[(to_uchar(in[0]) >> 3) & 0x1f];
+ if (!--outlen) {
+ break;
+ }
+ *out++ = b32str[((to_uchar(in[0]) << 2)
+ + (--inlen ? to_uchar(in[1]) >> 6 : 0))
+ & 0x1f];
+ if (!--outlen) {
+ break;
+ }
+ *out++ =(inlen
+ ? b32str[(to_uchar(in[1]) >> 1) & 0x1f]
+ : '=');
+ if (!--outlen) {
+ break;
+ }
+ *out++ = (inlen
+ ? b32str[((to_uchar(in[1]) << 4)
+ + (--inlen ? to_uchar(in[2]) >> 4 : 0))
+ & 0x1f]
+ : '=');
+ if (!--outlen) {
+ break;
+ }
+ *out++ = (inlen
+ ? b32str[((to_uchar(in[2]) << 1)
+ + (--inlen ? to_uchar(in[3]) >> 7 : 0))
+ & 0x1f]
+ : '=');
+ if (!--outlen) {
+ break;
+ }
+ *out++ = (inlen
+ ? b32str[(to_uchar(in[3]) >> 2) & 0x1f]
+ : '=');
+ if (!--outlen)
+ {
+ break;
+ }
+ *out++ = (inlen
+ ? b32str[((to_uchar(in[3]) << 3)
+ + (--inlen ? to_uchar(in[4]) >> 5 : 0))
+ & 0x1f]
+ : '=');
+ if (!--outlen) {
+ break;
+ }
+ *out++ = inlen ? b32str[to_uchar(in[4]) & 0x1f] : '=';
+ if (!--outlen) {
+ break;
+ }
+ if (inlen) {
+ inlen--;
+ }
+ if (inlen) {
+ in += 5;
+ }
+ }
+
+ if (outlen) {
+ *out = '\0';
+ }
+}
+
+/* Allocate a buffer and store zero terminated base32hex encoded data
+ from array IN of size INLEN, returning BASE32HEX_LENGTH(INLEN), i.e.,
+ the length of the encoded data, excluding the terminating zero. On
+ return, the OUT variable will hold a pointer to newly allocated
+ memory that must be deallocated by the caller. If output string
+ length would overflow, 0 is returned and OUT is set to NULL. If
+ memory allocation failed, OUT is set to NULL, and the return value
+ indicates length of the requested memory block, i.e.,
+ BASE32HEX_LENGTH(inlen) + 1. */
+size_t base32hex_encode_alloc(const char *in, size_t inlen, char **out)
+{
+ size_t outlen = 1 + BASE32HEX_LENGTH (inlen);
+
+ /* Check for overflow in outlen computation.
+ *
+ * If there is no overflow, outlen >= inlen.
+ *
+ * If the operation (inlen + 2) overflows then it yields at most +1, so
+ * outlen is 0.
+ *
+ * If the multiplication overflows, we lose at least half of the
+ * correct value, so the result is < ((inlen + 2) / 3) * 2, which is
+ * less than (inlen + 2) * 0.66667, which is less than inlen as soon as
+ * (inlen > 4).
+ */
+ if (inlen > outlen)
+ {
+ *out = NULL;
+ return 0;
+ }
+
+ *out = malloc(outlen);
+ if (!*out) {
+ return outlen;
+ }
+
+ base32hex_encode(in, inlen, *out, outlen);
+
+ return outlen - 1;
+}
+
+/* With this approach this file works independent of the charset used
+ (think EBCDIC). However, it does assume that the characters in the
+ Base32hex alphabet (A-Z2-7) are encoded in 0..255. POSIX
+ 1003.1-2001 require that char and unsigned char are 8-bit
+ quantities, though, taking care of that problem. But this may be a
+ potential problem on non-POSIX C99 platforms.
+
+ IBM C V6 for AIX mishandles "#define B32(x) ...'x'...", so use "_"
+ as the formal parameter rather than "x". */
+#define B32(_) \
+ ((_) == '0' ? 0 \
+ : (_) == '1' ? 1 \
+ : (_) == '2' ? 2 \
+ : (_) == '3' ? 3 \
+ : (_) == '4' ? 4 \
+ : (_) == '5' ? 5 \
+ : (_) == '6' ? 6 \
+ : (_) == '7' ? 7 \
+ : (_) == '8' ? 8 \
+ : (_) == '9' ? 9 \
+ : (_) == 'A' ? 10 \
+ : (_) == 'B' ? 11 \
+ : (_) == 'C' ? 12 \
+ : (_) == 'D' ? 13 \
+ : (_) == 'E' ? 14 \
+ : (_) == 'F' ? 15 \
+ : (_) == 'G' ? 16 \
+ : (_) == 'H' ? 17 \
+ : (_) == 'I' ? 18 \
+ : (_) == 'J' ? 19 \
+ : (_) == 'K' ? 20 \
+ : (_) == 'L' ? 21 \
+ : (_) == 'M' ? 22 \
+ : (_) == 'N' ? 23 \
+ : (_) == 'O' ? 24 \
+ : (_) == 'P' ? 25 \
+ : (_) == 'Q' ? 26 \
+ : (_) == 'R' ? 27 \
+ : (_) == 'S' ? 28 \
+ : (_) == 'T' ? 29 \
+ : (_) == 'U' ? 30 \
+ : (_) == 'V' ? 31 \
+ : (_) == 'a' ? 10 \
+ : (_) == 'b' ? 11 \
+ : (_) == 'c' ? 12 \
+ : (_) == 'd' ? 13 \
+ : (_) == 'e' ? 14 \
+ : (_) == 'f' ? 15 \
+ : (_) == 'g' ? 16 \
+ : (_) == 'h' ? 17 \
+ : (_) == 'i' ? 18 \
+ : (_) == 'j' ? 19 \
+ : (_) == 'k' ? 20 \
+ : (_) == 'l' ? 21 \
+ : (_) == 'm' ? 22 \
+ : (_) == 'n' ? 23 \
+ : (_) == 'o' ? 24 \
+ : (_) == 'p' ? 25 \
+ : (_) == 'q' ? 26 \
+ : (_) == 'r' ? 27 \
+ : (_) == 's' ? 28 \
+ : (_) == 't' ? 29 \
+ : (_) == 'u' ? 30 \
+ : (_) == 'v' ? 31 \
+ : -1)
+
+static const signed char b32[0x100] = {
+ B32 (0), B32 (1), B32 (2), B32 (3),
+ B32 (4), B32 (5), B32 (6), B32 (7),
+ B32 (8), B32 (9), B32 (10), B32 (11),
+ B32 (12), B32 (13), B32 (14), B32 (15),
+ B32 (16), B32 (17), B32 (18), B32 (19),
+ B32 (20), B32 (21), B32 (22), B32 (23),
+ B32 (24), B32 (25), B32 (26), B32 (27),
+ B32 (28), B32 (29), B32 (30), B32 (31),
+ B32 (32), B32 (33), B32 (34), B32 (35),
+ B32 (36), B32 (37), B32 (38), B32 (39),
+ B32 (40), B32 (41), B32 (42), B32 (43),
+ B32 (44), B32 (45), B32 (46), B32 (47),
+ B32 (48), B32 (49), B32 (50), B32 (51),
+ B32 (52), B32 (53), B32 (54), B32 (55),
+ B32 (56), B32 (57), B32 (58), B32 (59),
+ B32 (60), B32 (61), B32 (62), B32 (63),
+ B32 (64), B32 (65), B32 (66), B32 (67),
+ B32 (68), B32 (69), B32 (70), B32 (71),
+ B32 (72), B32 (73), B32 (74), B32 (75),
+ B32 (76), B32 (77), B32 (78), B32 (79),
+ B32 (80), B32 (81), B32 (82), B32 (83),
+ B32 (84), B32 (85), B32 (86), B32 (87),
+ B32 (88), B32 (89), B32 (90), B32 (91),
+ B32 (92), B32 (93), B32 (94), B32 (95),
+ B32 (96), B32 (97), B32 (98), B32 (99),
+ B32 (100), B32 (101), B32 (102), B32 (103),
+ B32 (104), B32 (105), B32 (106), B32 (107),
+ B32 (108), B32 (109), B32 (110), B32 (111),
+ B32 (112), B32 (113), B32 (114), B32 (115),
+ B32 (116), B32 (117), B32 (118), B32 (119),
+ B32 (120), B32 (121), B32 (122), B32 (123),
+ B32 (124), B32 (125), B32 (126), B32 (127),
+ B32 (128), B32 (129), B32 (130), B32 (131),
+ B32 (132), B32 (133), B32 (134), B32 (135),
+ B32 (136), B32 (137), B32 (138), B32 (139),
+ B32 (140), B32 (141), B32 (142), B32 (143),
+ B32 (144), B32 (145), B32 (146), B32 (147),
+ B32 (148), B32 (149), B32 (150), B32 (151),
+ B32 (152), B32 (153), B32 (154), B32 (155),
+ B32 (156), B32 (157), B32 (158), B32 (159),
+ B32 (160), B32 (161), B32 (162), B32 (163),
+ B32 (164), B32 (165), B32 (166), B32 (167),
+ B32 (168), B32 (169), B32 (170), B32 (171),
+ B32 (172), B32 (173), B32 (174), B32 (175),
+ B32 (176), B32 (177), B32 (178), B32 (179),
+ B32 (180), B32 (181), B32 (182), B32 (183),
+ B32 (184), B32 (185), B32 (186), B32 (187),
+ B32 (188), B32 (189), B32 (190), B32 (191),
+ B32 (192), B32 (193), B32 (194), B32 (195),
+ B32 (196), B32 (197), B32 (198), B32 (199),
+ B32 (200), B32 (201), B32 (202), B32 (203),
+ B32 (204), B32 (205), B32 (206), B32 (207),
+ B32 (208), B32 (209), B32 (210), B32 (211),
+ B32 (212), B32 (213), B32 (214), B32 (215),
+ B32 (216), B32 (217), B32 (218), B32 (219),
+ B32 (220), B32 (221), B32 (222), B32 (223),
+ B32 (224), B32 (225), B32 (226), B32 (227),
+ B32 (228), B32 (229), B32 (230), B32 (231),
+ B32 (232), B32 (233), B32 (234), B32 (235),
+ B32 (236), B32 (237), B32 (238), B32 (239),
+ B32 (240), B32 (241), B32 (242), B32 (243),
+ B32 (244), B32 (245), B32 (246), B32 (247),
+ B32 (248), B32 (249), B32 (250), B32 (251),
+ B32 (252), B32 (253), B32 (254), B32 (255)
+};
+
+#if UCHAR_MAX == 255
+#define uchar_in_range(c) true
+#else
+#define uchar_in_range(c) ((c) <= 255)
+#endif
+
+/* Return true if CH is a character from the Base32hex alphabet, and
+ false otherwise. Note that '=' is padding and not considered to be
+ part of the alphabet. */
+bool isbase32hex(char ch)
+{
+ return uchar_in_range(to_uchar(ch)) && 0 <= b32[to_uchar(ch)];
+}
+
+/* Decode base32hex encoded input array IN of length INLEN to output
+ array OUT that can hold *OUTLEN bytes. Return true if decoding was
+ successful, i.e. if the input was valid base32hex data, false
+ otherwise. If *OUTLEN is too small, as many bytes as possible will
+ be written to OUT. On return, *OUTLEN holds the length of decoded
+ bytes in OUT. Note that as soon as any non-alphabet characters are
+ encountered, decoding is stopped and false is returned. This means
+ that, when applicable, you must remove any line terminators that is
+ part of the data stream before calling this function. */
+bool base32hex_decode(const char *in, size_t inlen, char *out, size_t *outlen)
+{
+ size_t outleft = *outlen;
+
+ while (inlen >= 2) {
+ if (!isbase32hex(in[0]) || !isbase32hex(in[1])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ = ((b32[to_uchar(in[0])] << 3)
+ | (b32[to_uchar(in[1])] >> 2));
+ outleft--;
+ }
+
+ if (inlen == 2) {
+ break;
+ }
+
+ if (in[2] == '=') {
+ if (inlen != 8) {
+ break;
+ }
+
+ if ((in[3] != '=') ||
+ (in[4] != '=') ||
+ (in[5] != '=') ||
+ (in[6] != '=') ||
+ (in[7] != '=')) {
+ break;
+ }
+ } else {
+ if (!isbase32hex(in[2]) || !isbase32hex(in[3])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ = ((b32[to_uchar(in[1])] << 6)
+ | ((b32[to_uchar(in[2])] << 1) & 0x3E)
+ | (b32[to_uchar(in[3])] >> 4));
+ outleft--;
+ }
+
+ if (inlen == 4) {
+ break;
+ }
+
+ if (in[4] == '=') {
+ if (inlen != 8) {
+ break;
+ }
+
+ if ((in[5] != '=') ||
+ (in[6] != '=') ||
+ (in[7] != '=')) {
+ break;
+ }
+ } else {
+ if (!isbase32hex (in[3]) || !isbase32hex(in[4])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ = ((b32[to_uchar(in[3])] << 4)
+ | (b32[to_uchar(in[4])] >> 1));
+ outleft--;
+ }
+
+ if (inlen == 5) {
+ break;
+ }
+
+ if (in[5] == '=') {
+ if (inlen != 8) {
+ break;
+ }
+
+ if ((in[6] != '=')
+ || (in[7] != '=')) {
+ break;
+ }
+ } else {
+ if (!isbase32hex (in[5])
+ || !isbase32hex (in[6])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ = ((b32[to_uchar(in[4])]
+ << 7)
+ | (b32[to_uchar(in[5])] << 2)
+ | (b32[to_uchar(in[6])]
+ >> 3));
+ outleft--;
+ }
+
+ if (inlen == 7) {
+ break;
+ }
+
+ if (in[7] == '=') {
+ if (inlen != 8) {
+ break;
+ }
+ } else {
+ if (!isbase32hex (in[7])) {
+ break;
+ }
+
+ if (outleft) {
+ *out++ =
+ ((b32[to_uchar(in[6])]
+ << 5) | (b32[
+ to_uchar(in[7])]));
+ outleft--;
+ }
+ }
+ }
+ }
+ }
+
+ in += 8;
+ inlen -= 8;
+ }
+
+ *outlen -= outleft;
+
+ if (inlen != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Allocate an output buffer in *OUT, and decode the base32hex encoded
+ data stored in IN of size INLEN to the *OUT buffer. On return, the
+ size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
+ if the caller is not interested in the decoded length. *OUT may be
+ NULL to indicate an out of memory error, in which case *OUTLEN
+ contains the size of the memory block needed. The function returns
+ true on successful decoding and memory allocation errors. (Use the
+ *OUT and *OUTLEN parameters to differentiate between successful
+ decoding and memory error.) The function returns false if the
+ input was invalid, in which case *OUT is NULL and *OUTLEN is
+ undefined. */
+bool base32hex_decode_alloc(const char *in, size_t inlen, char **out,
+ size_t *outlen)
+{
+ /* This may allocate a few bytes too much, depending on input,
+ but it's not worth the extra CPU time to compute the exact amount.
+ The exact amount is 5 * inlen / 8, minus 1 if the input ends
+ with "=" and minus another 1 if the input ends with "==", etc.
+ Dividing before multiplying avoids the possibility of overflow. */
+ size_t needlen = 5 * (inlen / 8) + 4;
+
+ *out = malloc(needlen);
+ if (!*out) {
+ return true;
+ }
+
+ if (!base32hex_decode(in, inlen, *out, &needlen)) {
+ free (*out);
+ *out = NULL;
+ return false;
+ }
+
+ if (outlen) {
+ *outlen = needlen;
+ }
+
+ return true;
+}
+
+#ifdef MAIN
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include "base32hex.h"
+
+int main(int argc, char **argv) {
+ int i = 1;
+ size_t inlen, outlen, argvlen;
+ char *out;
+ char *in;
+ bool ok;
+
+ while (argc > 1) {
+ argv++; argc--;
+ argvlen = strlen(*argv);
+
+ outlen = base32hex_encode_alloc(*argv, argvlen, &out);
+
+ if (out == NULL && outlen == 0 && inlen != 0) {
+ fprintf(stderr, "ERROR(encode): input too long: %zd\n",
+ outlen);
+ return 1;
+ }
+
+ if (out == NULL) {
+ fprintf(stderr, "ERROR(encode): memory allocation error"
+ "\n");
+ return 1;
+ }
+
+ ok = base32hex_decode_alloc(out, outlen, &in, &inlen);
+
+ if (!ok) {
+ fprintf(stderr, "ERROR(decode): input was not valid "
+ "base32hex: `%s'\n", out);
+ return 1;
+ }
+
+ if (in == NULL) {
+ fprintf(stderr, "ERROR(decode): memory allocation "
+ "error\n");
+ }
+
+ if ((inlen != argvlen) ||
+ strcmp(*argv, in) != 0) {
+ fprintf(stderr, "ERROR(encode/decode): input `%s' and "
+ "output `%s'\n", *argv, in);
+ return 1;
+ }
+ printf("INPUT: `%s'\nENCODE: `%s'\nDECODE: `%s'\n", *argv, out,
+ in);
+ }
+}
+
+#endif
diff --git a/src/common/base32hex.h b/src/common/base32hex.h
new file mode 100644
index 0000000..9ac4fa8
--- /dev/null
+++ b/src/common/base32hex.h
@@ -0,0 +1,124 @@
+/* base32hex.h -- Encode binary data using printable characters.
+ Copyright (C) 2004, 2005, 2006, 2010 Free Software Foundation, Inc.
+ Written by Ondřej Surý & Simon Josefsson.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _BASE32HEX_H_
+#define _BASE32HEX_H_
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get bool. */
+#include <stdbool.h>
+
+/*!
+ * \brief Counts the size of the Base32Hex-encoded output for given input
+ * length.
+ *
+ * \note This uses that the expression (n+(k-1))/k means the smallest
+ * integer >= n/k, i.e., the ceiling of n/k.
+ */
+#define BASE32HEX_LENGTH(inlen) ((((inlen) + 4) / 5) * 8)
+
+/*!
+ * \brief Checks if the given character belongs to the Base32Hex alphabet.
+ *
+ * \param ch Character to check.
+ *
+ * \retval true if \a ch belongs to the Base32Hex alphabet.
+ * \retval false otherwise.
+ */
+extern bool isbase32hex(char ch);
+
+/*!
+ * \brief Encodes the given character array using Base32 encoding with extended
+ * hex alphabet.
+ *
+ * If \a outlen is less than BASE32HEX_LENGTH(\a inlen), the function writes as
+ * many bytes as possible to the output buffer. If \a outlen is more than
+ * BASE32HEX_LENGTH(\a inlen), the output will be zero-terminated.
+ *
+ * \param in Input array of characters.
+ * \param inlen Length of the input array.
+ * \param out Output buffer.
+ * \param outlen Size of the output buffer.
+ */
+extern void base32hex_encode(const char *in, size_t inlen, char *out,
+ size_t outlen);
+
+/*!
+ * \brief Encodes the given character array using Base32 encoding with extended
+ * hex alphabet and allocates space for the output.
+ *
+ * \param in Input array of characters.
+ * \param inlen Length of the input array.
+ * \param out Output buffer.
+ *
+ * \return Size of the allocated output buffer (0 if failed).
+ */
+extern size_t base32hex_encode_alloc(const char *in, size_t inlen, char **out);
+
+/*!
+ * \brief Decodes the given character array in Base32 encoding with extended
+ * hex alphabet.
+ *
+ * If \a *outlen is too small, as many bytes as possible will be written to
+ * \a out. On return, \a *outlen holds the length of decoded bytes in \a out.
+ *
+ * \note As soon as any non-alphabet characters are encountered, decoding is
+ * stopped and false is returned. This means that, when applicable, you
+ * must remove any line terminators that is part of the data stream before
+ * calling this function.
+ *
+ * \param in Input array of characters.
+ * \param inlen Length of the input array.
+ * \param out Output buffer.
+ * \param outlen Size of the output buffer.
+ *
+ * \retval true if decoding was successful, i.e. if the input was valid
+ * base32hex data.
+ * \retval false otherwise.
+ */
+extern bool base32hex_decode(const char *in, size_t inlen, char *out,
+ size_t *outlen);
+
+/*!
+ * \brief Allocate an output buffer and decode the base32hex encoded data to it.
+ *
+ * On return, the size of the decoded data is stored in \a *outlen. \a outlen
+ * may be NULL, if the caller is not interested in the decoded length. \a *out
+ * may be NULL to indicate an out of memory error, in which case \a *outlen
+ * contains the size of the memory block needed.
+ *
+ * \param in Input array of characters.
+ * \param inlen Length of the input array.
+ * \param out Output buffer. \a *out may be NULL to indicate an out of memory
+ * error in which case \a *outlen contains the size of the memory
+ * block needed
+ * \param outlen Size of the output buffer. May be NULL, if the caller is not
+ * interested in the decoded length
+ *
+ * \retval true on successful decoding and memory allocation errors. (Use the
+ * \a *out and \a *outlen parameters to differentiate between
+ * successful decoding and memory error.)
+ * \retval false if the input was invalid, in which case \a *out is NULL and
+ * \a *outlen is undefined.
+ */
+extern bool base32hex_decode_alloc(const char *in, size_t inlen, char **out,
+ size_t *outlen);
+
+#endif /* _BASE32HEX_H_ */
diff --git a/src/common/crc.c b/src/common/crc.c
new file mode 100644
index 0000000..33bf903
--- /dev/null
+++ b/src/common/crc.c
@@ -0,0 +1,155 @@
+/*
+ Copyright (c) 2006-2011, Thomas Pircher <tehpeh@gmx.net>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+/**
+ * \file crc.c
+ * Functions and types for CRC checks.
+ *
+ * Generated on Fri May 6 11:25:47 2011,
+ * by pycrc v0.7.7, http://www.tty1.net/pycrc/
+ * using the configuration:
+ * Width = 32
+ * Poly = 0x04c11db7
+ * XorIn = 0xffffffff
+ * ReflectIn = True
+ * XorOut = 0xffffffff
+ * ReflectOut = True
+ * Algorithm = table-driven
+ *****************************************************************************/
+#include "crc.h"
+#include <stdint.h>
+#include <stdlib.h>
+
+/**
+ * Static table used for the table_driven implementation.
+ *****************************************************************************/
+static const crc_t crc_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+/**
+ * Reflect all bits of a \a data word of \a data_len bytes.
+ *
+ * \param data The data word to be reflected.
+ * \param data_len The width of \a data expressed in number of bits.
+ * \return The reflected data.
+ *****************************************************************************/
+crc_t crc_reflect(crc_t data, size_t data_len)
+{
+ unsigned int i;
+ crc_t ret;
+
+ ret = data & 0x01;
+ for (i = 1; i < data_len; i++) {
+ data >>= 1;
+ ret = (ret << 1) | (data & 0x01);
+ }
+ return ret;
+}
+
+
+/**
+ * Update the crc value with new data.
+ *
+ * \param crc The current crc value.
+ * \param data Pointer to a buffer of \a data_len bytes.
+ * \param data_len Number of bytes in the \a data buffer.
+ * \return The updated crc value.
+ *****************************************************************************/
+crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len)
+{
+ unsigned int tbl_idx;
+
+ while (data_len--) {
+ tbl_idx = (crc ^ *data) & 0xff;
+ crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
+
+ data++;
+ }
+ return crc & 0xffffffff;
+}
+
+
+
diff --git a/src/common/crc.h b/src/common/crc.h
new file mode 100644
index 0000000..41971a9
--- /dev/null
+++ b/src/common/crc.h
@@ -0,0 +1,110 @@
+/*
+ Copyright (c) 2006-2011, Thomas Pircher <tehpeh@gmx.net>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+/**
+ * \file crc.h
+ * Functions and types for CRC checks.
+ *
+ * Generated on Fri May 6 11:25:43 2011,
+ * by pycrc v0.7.7, http://www.tty1.net/pycrc/
+ * using the configuration:
+ * Width = 32
+ * Poly = 0x04c11db7
+ * XorIn = 0xffffffff
+ * ReflectIn = True
+ * XorOut = 0xffffffff
+ * ReflectOut = True
+ * Algorithm = table-driven
+ *****************************************************************************/
+#ifndef __CRC_H__
+#define __CRC_H__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * The definition of the used algorithm.
+ *****************************************************************************/
+#define CRC_ALGO_TABLE_DRIVEN 1
+
+
+/**
+ * The type of the CRC values.
+ *
+ * This type must be big enough to contain at least 32 bits.
+ *****************************************************************************/
+typedef uint32_t crc_t;
+
+
+/**
+ * Reflect all bits of a \a data word of \a data_len bytes.
+ *
+ * \param data The data word to be reflected.
+ * \param data_len The width of \a data expressed in number of bits.
+ * \return The reflected data.
+ *****************************************************************************/
+crc_t crc_reflect(crc_t data, size_t data_len);
+
+
+/**
+ * Calculate the initial crc value.
+ *
+ * \return The initial crc value.
+ *****************************************************************************/
+static inline crc_t crc_init(void)
+{
+ return 0xffffffff;
+}
+
+
+/**
+ * Update the crc value with new data.
+ *
+ * \param crc The current crc value.
+ * \param data Pointer to a buffer of \a data_len bytes.
+ * \param data_len Number of bytes in the \a data buffer.
+ * \return The updated crc value.
+ *****************************************************************************/
+crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len);
+
+
+/**
+ * Calculate the final crc value.
+ *
+ * \param crc The current crc value.
+ * \return The final crc value.
+ *****************************************************************************/
+static inline crc_t crc_finalize(crc_t crc)
+{
+ return crc ^ 0xffffffff;
+}
+
+
+#ifdef __cplusplus
+} /* closing brace for extern "C" */
+#endif
+
+#endif /* __CRC_H__ */
diff --git a/src/common/dynamic-array.c b/src/common/dynamic-array.c
new file mode 100644
index 0000000..1e2efac
--- /dev/null
+++ b/src/common/dynamic-array.c
@@ -0,0 +1,224 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <pthread.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <urcu.h>
+
+//#include "common.h"
+#include "common/dynamic-array.h"
+
+#ifndef ERR_ALLOC_FAILED
+#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d\n", \
+ __FILE__, __LINE__)
+#endif
+
+//#define DA_DEBUG
+
+#ifndef dbg_da
+#ifdef DA_DEBUG
+#define dbg_da(msg...) fprintf(stderr, msg)
+#else
+#define dbg_da(msg...)
+#endif
+#endif
+
+/*----------------------------------------------------------------------------*/
+/* Private functions */
+/*----------------------------------------------------------------------------*/
+
+enum da_resize_type {
+ DA_LARGER, DA_SMALLER
+};
+
+typedef enum da_resize_type da_resize_type_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \retval 1 On success.
+ * \retval -1 On failure.
+ */
+static int da_resize(da_array_t *array, da_resize_type_t type)
+{
+ dbg_da("da_resize(): array pointer: %p, items pointer: %p\n", array,
+ array->items);
+
+ unsigned new_size = ((type == DA_LARGER)
+ ? (array->allocated *= 2)
+ : (array->allocated /= 2));
+
+ void *new_items = malloc(new_size * array->item_size);
+ if (new_items == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ dbg_da("Place for new items: %p\n", new_items);
+
+ // copy the contents from the old array to the new
+ memcpy(new_items, array->items, array->count * array->item_size);
+
+ // do RCU update
+ void *old_items = rcu_xchg_pointer(&array->items, new_items);
+ array->allocated = new_size;
+
+ dbg_da("Old items pointer: %p\n", old_items);
+
+ // wait for readers to finish
+ synchronize_rcu();
+ // deallocate the old array
+ dbg_da("RCU synchronized, deallocating old items array at address %p."
+ "\n", old_items);
+ free(old_items);
+
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Public functions */
+/*----------------------------------------------------------------------------*/
+
+da_array_t *da_create(unsigned count, size_t item_size)
+{
+ da_array_t *a = (da_array_t *)malloc(sizeof(da_array_t));
+ if (a == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ da_initialize(a, count, item_size);
+ return a;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int da_initialize(da_array_t *array, unsigned count, size_t item_size)
+{
+ assert(array != NULL);
+ pthread_mutex_init(&array->mtx, NULL);
+ pthread_mutex_lock(&array->mtx);
+
+ array->items = malloc(count * item_size);
+ if (array->items == NULL) {
+ array->allocated = 0;
+ array->count = 0;
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ array->allocated = count;
+ array->count = 0;
+ array->item_size = item_size;
+ memset(array->items, 0, count * item_size);
+
+ pthread_mutex_unlock(&array->mtx);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int da_reserve(da_array_t *array, unsigned count)
+{
+ pthread_mutex_lock(&array->mtx);
+ unsigned res = 0;
+
+ assert(array->allocated >= array->count);
+ if ((array->allocated - array->count) >= count) {
+ dbg_da("Enough place in the array, no resize needed.\n");
+ res = 0;
+ } else {
+ dbg_da("Resizing array.\n");
+ res = da_resize(array, DA_LARGER);
+ }
+ pthread_mutex_unlock(&array->mtx);
+
+ return res;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int da_occupy(da_array_t *array, unsigned count)
+{
+ pthread_mutex_lock(&array->mtx);
+ unsigned res = 0;
+ assert(array->allocated >= array->count);
+
+ if ((array->allocated - array->count) < count) {
+ dbg_da("Not enough place to occupy.\n");
+ res = -1;
+ } else {
+ array->count += count;
+ }
+
+ pthread_mutex_unlock(&array->mtx);
+ return res;
+}
+
+/*----------------------------------------------------------------------------*/
+
+unsigned da_try_reserve(const da_array_t *array, unsigned count)
+{
+ assert(array->allocated >= array->count);
+ if ((array->allocated - array->count) >= count) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void da_release(da_array_t *array, unsigned count)
+{
+ pthread_mutex_lock(&array->mtx);
+
+ assert(array->allocated >= array->count);
+ assert(array->count >= count);
+ dbg_da("Decreasing count of items in array.\n");
+ array->count -= count;
+
+ pthread_mutex_unlock(&array->mtx);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void da_destroy(da_array_t *array)
+{
+ pthread_mutex_lock(&array->mtx);
+ void *old_items = rcu_dereference(array->items);
+ rcu_set_pointer(&array->items, NULL);
+ pthread_mutex_unlock(&array->mtx);
+
+ synchronize_rcu();
+ free(old_items);
+ pthread_mutex_destroy(&array->mtx);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void *da_get_items(const da_array_t *array)
+{
+ return array->items;
+}
+
+/*----------------------------------------------------------------------------*/
+
+unsigned da_get_count(const da_array_t *array)
+{
+ return array->count;
+}
diff --git a/src/common/dynamic-array.h b/src/common/dynamic-array.h
new file mode 100644
index 0000000..77a5d13
--- /dev/null
+++ b/src/common/dynamic-array.h
@@ -0,0 +1,156 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file dynamic-array.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Safe dynamic array implementation.
+ *
+ * \todo Somehow check if the array is initialized and do not use otherwise.
+ * Maybe some magic, or so.
+ * \todo This structure is too slow because of the mutex.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_DYNAMIC_ARRAY_H_
+#define _KNOTD_COMMON_DYNAMIC_ARRAY_H_
+
+#include <string.h>
+#include <pthread.h>
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Dynamic array structure.
+ *
+ * Before using the dynamic array, it must be initialized using da_initialize().
+ * When getting individual items always use da_get_items() to obtain pointer to
+ * the actual array.
+ *
+ * Items in the array cannot be dereferenced (it uses void * for storing the
+ * the items). It is needed to type-cast the item array (obtained by calling
+ * da_get_items()) to a proper type before dereferencing.
+ *
+ * When adding items, first reserve enough space for them by callling
+ * da_reserve() and subsequently tell the array about the inserted items by
+ * calling da_occupy(). When removing, the array must be told about the fact
+ * by calling da_release().
+ *
+ * For getting the actual number of items in array use da_get_count().
+ *
+ * When the array is no more needed, the da_destroy() function must be called
+ * before deallocating the structure.
+ */
+struct da_array {
+ /*! \brief The actual array. The items can't be dereferenced directly.*/
+ void *items;
+
+ /*!
+ * \brief Size of the stored items in bytes (used in counting of space
+ * needed.
+ */
+ size_t item_size;
+
+ /*!
+ * \brief Size of allocated space in number of items that can be stored.
+ */
+ unsigned allocated;
+
+ /*! \brief Number of items actually stored in the array. */
+ unsigned count;
+
+ /*! \brief Mutex. */
+ pthread_mutex_t mtx;
+};
+
+typedef struct da_array da_array_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates and initializes the dynamic array.
+ *
+ * Initialization comprises of allocating place for \a count items of size
+ * \a item_size and setting the items to zeros.
+ *
+ * \retval 0 if successful.
+ * \retval -1 if not successful.
+ */
+da_array_t *da_create(unsigned count, size_t item_size);
+
+/*!
+ * \brief Initializes the dynamic array.
+ *
+ * Initialization comprises of allocating place for \a count items of size
+ * \a item_size and setting the items to zeros.
+ *
+ * \retval 0 if successful.
+ * \retval -1 if not successful.
+ */
+int da_initialize(da_array_t *array, unsigned count, size_t item_size);
+
+/*!
+ * \brief Reserves space for \a count more items.
+ *
+ * \retval 0 if successful and resizing was not necessary.
+ * \retval 1 if successful and the array was enlarged.
+ * \retval -1 if not successful - resizing was needed but could not be done.
+ */
+int da_reserve(da_array_t *array, unsigned count);
+
+/*!
+ * \brief Increases the number of items in array by \a count.
+ *
+ * \retval 0 If successful.
+ * \retval -1 If not successful (not enough allocated space, i.e. must run
+ * da_reserve()).
+ */
+int da_occupy(da_array_t *array, unsigned count);
+
+/*!
+ * \brief Tries to reserve space for \a count more items.
+ *
+ * \retval 0 if successful and resizing is not necessary.
+ * \retval 1 if successful but the array will need to be resized.
+ */
+unsigned da_try_reserve(const da_array_t *array, unsigned count);
+
+/*!
+ * \brief Releases space taken by \a count items.
+ */
+void da_release(da_array_t *array, unsigned count);
+
+/*!
+ * \brief Poperly deallocates the array.
+ */
+void da_destroy(da_array_t *array);
+
+/*!
+ * \brief Returns the array of items as a void *.
+ */
+void *da_get_items(const da_array_t *array);
+
+/*!
+ * \brief Returns count of items in the array.
+ */
+unsigned da_get_count(const da_array_t *array);
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* _KNOTD_COMMON_DYNAMIC_ARRAY_H_ */
+
+/*! @} */
diff --git a/src/common/errors.c b/src/common/errors.c
new file mode 100644
index 0000000..f1e650d
--- /dev/null
+++ b/src/common/errors.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common/errors.h"
+
+/*!
+ * \brief Looks up the given id in the lookup table.
+ *
+ * \param table Lookup table.
+ * \param id ID to look up.
+ *
+ * \return Item in the lookup table with the given id or NULL if no such is
+ * present.
+ */
+static const error_table_t *error_lookup_by_id(const error_table_t *table,
+ int id)
+{
+ while (table->name != 0) {
+ if (table->id == id) {
+ return table;
+ }
+ table++;
+ }
+
+ return 0;
+}
+
+const char *error_to_str(const error_table_t *table, int code)
+{
+ const error_table_t *msg = error_lookup_by_id(table, code);
+ if (msg != 0) {
+ return msg->name;
+ } else {
+ return "Unknown error.";
+ }
+}
+
+int _map_errno(int fallback_value, int arg0, ...)
+{
+ /* Iterate all variable-length arguments. */
+ va_list ap;
+ va_start(ap, arg0);
+
+ /* KNOTD_ERROR serves as a sentinel. */
+ for (int c = arg0; c != 0; c = va_arg(ap, int)) {
+
+ /* Error code matches with mapped. */
+ if (c == errno) {
+ /* Return negative value of the code. */
+ return -abs(c);
+ }
+ }
+ va_end(ap);
+
+ /* Fallback error code. */
+ return fallback_value;
+}
diff --git a/src/common/errors.h b/src/common/errors.h
new file mode 100644
index 0000000..a2773ac
--- /dev/null
+++ b/src/common/errors.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file errors.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Error codes and function for getting error message.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_ERROR_H_
+#define _KNOTD_COMMON_ERROR_H_
+
+#include <errno.h>
+
+/*! \brief Error lookup table. */
+typedef struct error_table_t {
+ int id;
+ const char *name;
+} error_table_t;
+
+/*!
+ * \brief Returns error message for the given error code.
+ *
+ * \param table Table of error messages to use.
+ * \param code Error code.
+ *
+ * \return String containing the error message.
+ */
+const char *error_to_str(const error_table_t *table, int code);
+
+/*!
+ * \brief Safe errno mapper that automatically appends sentinel value.
+ *
+ * \see _map_errno()
+ *
+ * \param fallback_value Fallback error value (used if the code could not be
+ * mapped.
+ * \param err POSIX errno.
+ * \param ... List of handled codes.
+ *
+ * \return Mapped error code.
+ */
+#define map_errno(fallback_value, err...) _map_errno(fallback_value, err, 0)
+
+/*!
+ * \brief Returns a mapped POSIX errcode.
+ *
+ * \warning Last error must be 0, it serves as a sentinel value.
+ * Use map_errno() instead.
+ *
+ * \param fallback_value Fallback error value (used if the code could not be
+ * mapped.
+ * \param arg0 First mandatory argument.
+ * \param ... List of handled codes.
+ *
+ * \return Mapped error code.
+ */
+int _map_errno(int fallback_value, int arg0, ...);
+
+#endif /* _KNOTD_COMMON_ERROR_H_ */
+
+/*! @} */
diff --git a/src/common/evqueue.c b/src/common/evqueue.c
new file mode 100644
index 0000000..ca3027f
--- /dev/null
+++ b/src/common/evqueue.c
@@ -0,0 +1,130 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "common/evqueue.h"
+
+/*! \brief Singleton application-wide event queue. */
+evqueue_t *s_evqueue = 0;
+
+evqueue_t *evqueue_new()
+{
+ evqueue_t* q = malloc(sizeof(evqueue_t));
+
+ /* Initialize fds. */
+ if (pipe(q->fds) < 0) {
+ free(q);
+ q = 0;
+ }
+
+ return q;
+}
+
+void evqueue_free(evqueue_t **q)
+{
+ /* Check. */
+ if (!q) {
+ return;
+ }
+
+ /* Invalidate pointer to queue. */
+ evqueue_t *eq = *q;
+ *q = 0;
+
+ /* Deinitialize. */
+ close(eq->fds[EVQUEUE_READFD]);
+ close(eq->fds[EVQUEUE_WRITEFD]);
+ free(eq);
+}
+
+int evqueue_poll(evqueue_t *q, const struct timespec *ts,
+ const sigset_t *sigmask)
+{
+ /* Check. */
+ if (!q) {
+ return -1;
+ }
+
+ /* Prepare fd set. */
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(q->fds[EVQUEUE_READFD], &rfds);
+
+ /* Wait for events. */
+ int ret = pselect(q->fds[EVQUEUE_READFD] + 1, &rfds, 0, 0, ts, sigmask);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return ret;
+}
+
+int evqueue_read(evqueue_t *q, void *dst, size_t len)
+{
+ if (!q || !dst || len == 0) {
+ return -1;
+ }
+
+ return read(q->fds[EVQUEUE_READFD], dst, len);
+}
+
+int evqueue_write(evqueue_t *q, const void *src, size_t len)
+{
+ if (!q || !src || len == 0) {
+ return -1;
+ }
+
+ return write(q->fds[EVQUEUE_WRITEFD], src, len);
+}
+
+int evqueue_get(evqueue_t *q, event_t *ev)
+{
+ /* Check. */
+ if (!q || !ev) {
+ return -1;
+ }
+
+ /* Read data. */
+ int ret = evqueue_read(q, ev, sizeof(event_t));
+ if (ret != sizeof(event_t)) {
+ return -1;
+ }
+
+ /* Set parent. */
+ ev->parent = q;
+
+ return 0;
+}
+
+int evqueue_add(evqueue_t *q, const event_t *ev)
+{
+ /* Check. */
+ if (!q || !ev) {
+ return -1;
+ }
+
+ /* Write data. */
+ int ret = evqueue_write(q, ev, sizeof(event_t));
+ if (ret != sizeof(event_t)) {
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/src/common/evqueue.h b/src/common/evqueue.h
new file mode 100644
index 0000000..ffb3860
--- /dev/null
+++ b/src/common/evqueue.h
@@ -0,0 +1,200 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file evqueue.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Event queue.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_EVQUEUE_H_
+#define _KNOTD_COMMON_EVQUEUE_H_
+
+#include <pthread.h>
+#include <signal.h> // sigset_t
+#include <time.h>
+#include <sys/time.h>
+
+//#include "knot/common.h"
+#include "common/lists.h"
+
+struct event_t;
+
+/*!
+ * \brief Event callback.
+ *
+ * Pointer to whole event structure is passed to the callback.
+ * Callback should return 0 on success and negative integer on error.
+ *
+ * Example callback:
+ * \code
+ * int print_callback(event_t *t) {
+ * return printf("Callback: %s\n", t->data);
+ * }
+ * \endcode
+ */
+typedef int (*event_cb_t)(struct event_t *);
+
+/*!
+ * \brief Event structure.
+ */
+typedef struct event_t {
+ node n; /*!< Node for event queue. */
+ int type; /*!< Event type. */
+ struct timeval tv; /*!< Event scheduled time. */
+ void *data; /*!< Usable data ptr. */
+ event_cb_t cb; /*!< Event callback. */
+ void *parent; /*!< Pointer to parent (evqueue, scheduler...) */
+} event_t;
+
+/*!
+ * \brief Event queue constants.
+ */
+enum {
+ EVQUEUE_READFD = 0,
+ EVQUEUE_WRITEFD = 1
+};
+
+/*!
+ * \brief Event queue structure.
+ */
+typedef struct {
+ int fds[2]; /*!< Read and Write fds. */
+} evqueue_t;
+
+/*!
+ * \brief Create new event queue.
+ *
+ * Event queue is thread-safe and POSIX signal-safe.
+ * It uses piped fds for queueing and pselect(2) to
+ * wait for events.
+ *
+ * \retval New instance on success.
+ * \retval NULL on error.
+ */
+evqueue_t *evqueue_new();
+
+/*!
+ * \brief Deinitialize and free event queue.
+ *
+ * \param q Pointer to queue instance.
+ * \note *q is set to 0.
+ */
+void evqueue_free(evqueue_t **q);
+
+/*!
+ * \brief Poll for new events.
+ *
+ * Unblocked signals during polling are specified
+ * in a sigmask.
+ *
+ * \param q Event queue.
+ * \param ts Timeout (or NULL for infinite).
+ * \param sigmask Bitmask of signals to receive (or NULL).
+ *
+ * \retval Number of polled events on success.
+ * \retval -1 On error or signal interrupt.
+ */
+int evqueue_poll(evqueue_t *q, const struct timespec *ts, const sigset_t *sigmask);
+
+/*!
+ * \brief Return evqueue pollable fd.
+ *
+ * \param q Event queue.
+ *
+ * \retval File descriptor available for polling.
+ * \retval -1 On error.
+ */
+static inline int evqueue_pollfd(evqueue_t *q) {
+ return q->fds[EVQUEUE_READFD];
+}
+
+/*!
+ * \brief Read data from event queue.
+ *
+ * This function is useful for sending custom
+ * events or other data types through the event queue.
+ *
+ * \param q Event queue.
+ * \param dst Destination buffer.
+ * \param len Number of bytes to read.
+ *
+ * \retval Number of read bytes on success.
+ * \retval -1 on error, \see read(2).
+ */
+int evqueue_read(evqueue_t *q, void *dst, size_t len);
+
+/*!
+ * \brief Write data to event queue.
+ *
+ * This function is useful for sending custom
+ * events or other data types through the event queue.
+ *
+ * \param q Event queue.
+ * \param src Source buffer.
+ * \param len Number of bytes to write.
+ *
+ * \retval Number of written bytes on success.
+ * \retval -1 on error, \see write(2).
+ */
+int evqueue_write(evqueue_t *q, const void *src, size_t len);
+
+/*!
+ * \brief Read event from event queue.
+ *
+ * \param q Event queue.
+ * \param ev Event structure for writing.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int evqueue_get(evqueue_t *q, event_t *ev);
+
+/*!
+ * \brief Add event to queue.
+ *
+ * \param q Event queue.
+ * \param ev Event structure to read.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int evqueue_add(evqueue_t *q, const event_t *ev);
+
+/* Singleton event queue pointer. */
+extern evqueue_t *s_evqueue;
+
+/*!
+ * \brief Event queue singleton.
+ */
+static inline evqueue_t *evqueue() {
+ return s_evqueue;
+}
+
+/*!
+ * \brief Set event queue singleton.
+ */
+static inline void evqueue_set(evqueue_t *q) {
+ s_evqueue = q;
+}
+
+#endif /* _KNOTD_COMMON_EVQUEUE_H_ */
+
+/*! @} */
diff --git a/src/common/evsched.c b/src/common/evsched.c
new file mode 100644
index 0000000..4e56028
--- /dev/null
+++ b/src/common/evsched.c
@@ -0,0 +1,309 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "common/evsched.h"
+
+/*!
+ * \brief Set event timer to T (now) + dt miliseconds.
+ */
+static void evsched_settimer(event_t *e, uint32_t dt)
+{
+ if (!e) {
+ return;
+ }
+
+ /* Get absolute time T. */
+ gettimeofday(&e->tv, 0);
+
+ /* Add number of seconds. */
+ e->tv.tv_sec += dt / 1000;
+
+ /* Add the number of microseconds. */
+ e->tv.tv_usec += (dt % 1000) * 1000;
+
+ /* Check for overflow. */
+ while (e->tv.tv_usec > 999999) {
+ e->tv.tv_sec += 1;
+ e->tv.tv_usec -= 1 * 1000 * 1000;
+ }
+}
+
+/*! \brief Singleton application-wide event scheduler. */
+evsched_t *s_evsched = 0;
+
+evsched_t *evsched_new()
+{
+ evsched_t *s = malloc(sizeof(evsched_t));
+ if (!s) {
+ return 0;
+ }
+
+ /* Initialize event calendar. */
+ pthread_mutex_init(&s->rl, 0);
+ pthread_mutex_init(&s->mx, 0);
+ pthread_cond_init(&s->notify, 0);
+ pthread_mutex_init(&s->cache.lock, 0);
+ slab_cache_init(&s->cache.alloc, sizeof(event_t));
+ init_list(&s->calendar);
+ return s;
+}
+
+void evsched_delete(evsched_t **s)
+{
+ if (!s) {
+ return;
+ }
+ if (!*s) {
+ return;
+ }
+
+ /* Deinitialize event calendar. */
+ pthread_mutex_destroy(&(*s)->rl);
+ pthread_mutex_destroy(&(*s)->mx);
+ pthread_cond_destroy(&(*s)->notify);
+ node *n = 0, *nxt = 0;
+ WALK_LIST_DELSAFE(n, nxt, (*s)->calendar) {
+ evsched_event_free((*s), (event_t*)n);
+ }
+
+ /* Free allocator. */
+ slab_cache_destroy(&(*s)->cache.alloc);
+ pthread_mutex_destroy(&(*s)->cache.lock);
+
+ /* Free scheduler. */
+ free(*s);
+ *s = 0;
+}
+
+event_t *evsched_event_new(evsched_t *s, int type)
+{
+ if (!s) {
+ return 0;
+ }
+
+ /* Allocate. */
+ pthread_mutex_lock(&s->cache.lock);
+ event_t *e = slab_cache_alloc(&s->cache.alloc);
+ pthread_mutex_unlock(&s->cache.lock);
+
+ /* Initialize. */
+ memset(e, 0, sizeof(event_t));
+ e->type = type;
+ return e;
+}
+
+void evsched_event_free(evsched_t *s, event_t *ev)
+{
+ if (!s || !ev) {
+ return;
+ }
+
+ pthread_mutex_lock(&s->cache.lock);
+ slab_free(ev);
+ pthread_mutex_unlock(&s->cache.lock);
+}
+
+event_t* evsched_next(evsched_t *s)
+{
+ /* Check. */
+ if (!s) {
+ return 0;
+ }
+
+ /* Lock calendar. */
+ pthread_mutex_lock(&s->mx);
+
+ while(1) {
+
+ /* Check event queue. */
+ if (!EMPTY_LIST(s->calendar)) {
+
+ /* Get current time. */
+ struct timeval dt;
+ gettimeofday(&dt, 0);
+
+ /* Get next event. */
+ event_t *next_ev = HEAD(s->calendar);
+
+ /* Immediately return. */
+ if (timercmp(&dt, &next_ev->tv, >=)) {
+ rem_node(&next_ev->n);
+ pthread_mutex_unlock(&s->mx);
+ pthread_mutex_lock(&s->rl);
+ s->current = next_ev;
+ return next_ev;
+ }
+
+ /* Wait for next event or interrupt. Unlock calendar. */
+ struct timespec ts;
+ ts.tv_sec = next_ev->tv.tv_sec;
+ ts.tv_nsec = next_ev->tv.tv_usec * 1000L;
+ pthread_cond_timedwait(&s->notify, &s->mx, &ts);
+ } else {
+ /* Block until an event is scheduled. Unlock calendar.*/
+ pthread_cond_wait(&s->notify, &s->mx);
+ }
+ }
+
+ /* Unlock calendar, this shouldn't happen. */
+ pthread_mutex_unlock(&s->mx);
+ return 0;
+
+}
+
+int evsched_event_finished(evsched_t *s)
+{
+ if (!s) {
+ return -1;
+ }
+
+ /* Mark as finished. */
+ if (s->current) {
+ s->current = 0;
+ pthread_mutex_unlock(&s->rl);
+ return 0;
+ }
+
+ /* Finished event is not current. */
+ return -1;
+}
+
+int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt)
+{
+ if (!s || !ev || dt < 0) {
+ return -1;
+ }
+
+ /* Update event timer. */
+ evsched_settimer(ev, dt);
+
+ /* Lock calendar. */
+ pthread_mutex_lock(&s->mx);
+
+ /* Schedule event. */
+ node *n = 0, *prev = 0;
+ if (!EMPTY_LIST(s->calendar)) {
+ WALK_LIST(n, s->calendar) {
+ event_t* cur = (event_t *)n;
+ if (timercmp(&cur->tv, &ev->tv, <)) {
+ prev = n;
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* Append to list. */
+ ev->parent = s;
+ if (prev) {
+ insert_node(&ev->n, prev);
+ } else {
+ add_head(&s->calendar, &ev->n);
+ }
+
+
+ /* Unlock calendar. */
+ pthread_cond_signal(&s->notify);
+ pthread_mutex_unlock(&s->mx);
+
+ return 0;
+}
+
+event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t dt)
+{
+ if (!s) {
+ return 0;
+ }
+
+ /* Create event. */
+ event_t *e = evsched_event_new(s, EVSCHED_CB);
+ if (!e) {
+ return 0;
+ }
+ e->cb = cb;
+ e->data = data;
+
+ /* Schedule. */
+ if (evsched_schedule(s, e, dt) != 0) {
+ evsched_event_free(s, e);
+ e = 0;
+ }
+
+ return e;
+}
+
+event_t* evsched_schedule_term(evsched_t *s, uint32_t dt)
+{
+ if (!s) {
+ return 0;
+ }
+
+ /* Create event. */
+ event_t *e = evsched_event_new(s, EVSCHED_TERM);
+ if (!e) {
+ return 0;
+ }
+
+ /* Schedule. */
+ if (evsched_schedule(s, e, dt) != 0) {
+ evsched_event_free(s, e);
+ e = 0;
+ }
+
+ return e;
+}
+
+int evsched_cancel(evsched_t *s, event_t *ev)
+{
+ if (!s || !ev) {
+ return -1;
+ }
+
+ /* Lock calendar. */
+ pthread_mutex_lock(&s->mx);
+
+ /* Make sure not running. */
+ pthread_mutex_lock(&s->rl);
+
+ /* Find in list. */
+ event_t *n = 0;
+ int found = 0;
+ WALK_LIST(n, s->calendar) {
+ if (n == ev) {
+ found = 1;
+ break;
+ }
+ }
+
+ /* Remove from list. */
+ if (found) {
+ rem_node(&ev->n);
+ }
+
+ /* Enable running events. */
+ pthread_mutex_unlock(&s->rl);
+
+ /* Unlock calendar. */
+ pthread_cond_signal(&s->notify);
+ pthread_mutex_unlock(&s->mx);
+
+ return 0;
+}
+
diff --git a/src/common/evsched.h b/src/common/evsched.h
new file mode 100644
index 0000000..2a682e1
--- /dev/null
+++ b/src/common/evsched.h
@@ -0,0 +1,240 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file evsched.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Event scheduler.
+ *
+ * Scheduler works with the same event_t type as event queue.
+ * It is also thread-safe so the scheduler can run in a separate thread
+ * while events can be enqueued from different threads.
+ *
+ * Guideline is, that the scheduler run loop should exit with
+ * a special event type EVSCHED_TERM.
+ *
+ * Example usage:
+ * \code
+ * evsched_t *s = evsched_new();
+ *
+ * // Schedule myfunc() after 1000ms
+ * evsched_schedule_cb(s, myfunc, data, 1000)
+ *
+ * // Schedule termination event after 1500ms
+ * evsched_schedule_term(s, 1500);
+ *
+ * // Event scheduler main loop
+ * while (1) {
+ * // Wait for next scheduled event
+ * event_t *ev = evsched_next();
+ *
+ * // Break on termination event
+ * if (ev->type == EVSCHED_TERM) {
+ * evsched_event_free(s, ev);
+ * break;
+ * }
+ *
+ * // Execute and discard event
+ * if (ev->cb) {
+ * ev->cb(ev);
+ * }
+ * evsched_event_free(s, ev); // Free executed event
+ * }
+ *
+ * // Delete event scheduler
+ * evsched_delete(s);
+ * \endcode
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_EVSCHED_H_
+#define _KNOTD_COMMON_EVSCHED_H_
+
+#include <pthread.h>
+#include "common/slab/slab.h"
+#include "common/lists.h"
+#include "common/evqueue.h"
+
+/*!
+ * \brief Scheduler event types.
+ */
+typedef enum evsched_ev_t {
+ EVSCHED_NOOP = 0, /*!< No-op action, skip. */
+ EVSCHED_CB, /*!< Callback action. */
+ EVSCHED_TERM /*!< Terminal action, stop event scheduler. */
+} evsched_ev_t;
+
+/*!
+ * \brief Event scheduler structure.
+ *
+ * Keeps list of scheduled events. Events are executed in their scheduled
+ * time and kept in an ordered list (queue).
+ * Scheduler is terminated with a special EVSCHED_TERM event type.
+ */
+typedef struct {
+ pthread_mutex_t rl; /*!< Event running lock. */
+ event_t *current; /*!< Current running event. */
+ pthread_mutex_t mx; /*!< Event queue locking. */
+ pthread_cond_t notify; /*!< Event queue notification. */
+ list calendar; /*!< Event calendar. */
+ struct {
+ slab_cache_t alloc; /*!< Events SLAB cache. */
+ pthread_mutex_t lock; /*!< Events cache spin lock. */
+ } cache;
+} evsched_t;
+
+/*!
+ * \brief Create new event scheduler instance.
+ *
+ * \retval New instance on success.
+ * \retval NULL on error.
+ */
+evsched_t *evsched_new();
+
+/*!
+ * \brief Deinitialize and free event scheduler instance.
+ *
+ * \param s Pointer to event scheduler instance.
+ * \note *sched is set to 0.
+ */
+void evsched_delete(evsched_t **s);
+
+/*!
+ * \brief Create an empty event.
+ *
+ * \param s Pointer to event scheduler instance.
+ * \param type Event type.
+ * \retval New instance on success.
+ * \retval NULL on error.
+ */
+event_t *evsched_event_new(evsched_t *s, int type);
+
+/*!
+ * \brief Dispose event instance.
+ *
+ * \param s Pointer to event scheduler instance.
+ * \param ev Event instance.
+ */
+void evsched_event_free(evsched_t *s, event_t *ev);
+
+/*!
+ * \brief Fetch next-event.
+ *
+ * Scheduler may block until a next event is available.
+ * Send scheduler an EVSCHED_NOOP or EVSCHED_TERM event to unblock it.
+ *
+ * \warning Returned event must be marked as finished, or deadlock occurs.
+ *
+ * \param s Event scheduler.
+ *
+ * \retval Scheduled event.
+ * \retval NULL on error.
+ */
+event_t* evsched_next(evsched_t *s);
+
+/*!
+ * \brief Mark running event as finished.
+ *
+ * Need to call this after each event returned by evsched_next() is finished.
+ *
+ * \param s Event scheduler.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int evsched_event_finished(evsched_t *s);
+
+/*!
+ * \brief Schedule an event.
+ *
+ * \param s Event scheduler.
+ * \param ev Prepared event.
+ * \param dt Time difference in milliseconds from now (dt is relative).
+ *
+ * \retval 0 on success.
+ * \retval <0 on error.
+ */
+int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt);
+
+/*!
+ * \brief Schedule callback event.
+ *
+ * Execute callback after dt miliseconds has passed.
+ *
+ * \param s Event scheduler.
+ * \param cb Callback handler.
+ * \param data Data for callback.
+ * \param dt Time difference in milliseconds from now (dt is relative).
+ *
+ * \retval Event instance on success.
+ * \retval NULL on error.
+ */
+event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t dt);
+
+/*!
+ * \brief Schedule termination event.
+ *
+ * Special action for scheduler termination.
+ *
+ * \param s Event scheduler.
+ * \param dt Time difference in milliseconds from now (dt is relative).
+ *
+ * \retval Event instance on success.
+ * \retval NULL on error.
+ */
+event_t* evsched_schedule_term(evsched_t *s, uint32_t dt);
+
+/*!
+ * \brief Cancel a scheduled event.
+ *
+ * \warning May block until current running event is finished (as it cannot
+ * interrupt running event).
+ *
+ * \warning Never cancel event in it's callback. As it never finishes,
+ * it deadlocks.
+ *
+ * \param s Event scheduler.
+ * \param ev Scheduled event.
+ *
+ * \retval 0 on success.
+ * \retval <0 on error.
+ */
+int evsched_cancel(evsched_t *s, event_t *ev);
+
+/* Singleton event scheduler pointer. */
+extern evsched_t *s_evsched;
+
+/*!
+ * \brief Event scheduler singleton.
+ */
+static inline evsched_t *evsched() {
+ return s_evsched;
+}
+
+/*!
+ * \brief Set event scheduler singleton.
+ */
+static inline void evsched_set(evsched_t *s) {
+ s_evsched = s;
+}
+
+
+#endif /* _KNOTD_COMMON_EVSCHED_H_ */
+
+/*! @} */
diff --git a/src/common/fdset.c b/src/common/fdset.c
new file mode 100644
index 0000000..8c070ad
--- /dev/null
+++ b/src/common/fdset.c
@@ -0,0 +1,80 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* Required for RTLD_DEFAULT. */
+#endif
+
+#include <dlfcn.h>
+#include <string.h>
+#include <stdio.h>
+#include "common/fdset.h"
+#include <config.h>
+
+struct fdset_backend_t _fdset_backend = {
+};
+
+/*! \brief Set backend implementation. */
+static void fdset_set_backend(struct fdset_backend_t *backend) {
+ memcpy(&_fdset_backend, backend, sizeof(struct fdset_backend_t));
+}
+
+/* Linux epoll API. */
+#ifdef HAVE_EPOLL_WAIT
+ #include "common/fdset_epoll.h"
+#endif /* HAVE_EPOLL_WAIT */
+
+/* BSD kqueue API */
+#ifdef HAVE_KQUEUE
+ #include "common/fdset_kqueue.h"
+#endif /* HAVE_KQUEUE */
+
+/* POSIX poll API */
+#ifdef HAVE_POLL
+ #include "common/fdset_poll.h"
+#endif /* HAVE_POLL */
+
+/*! \brief Bootstrap polling subsystem (it is called automatically). */
+void __attribute__ ((constructor)) fdset_init()
+{
+ /* Preference: epoll */
+#ifdef HAVE_EPOLL_WAIT
+ if (dlsym(RTLD_DEFAULT, "epoll_wait") != 0) {
+ fdset_set_backend(&FDSET_EPOLL);
+ return;
+ }
+#endif
+
+ /* Preference: kqueue */
+#ifdef HAVE_KQUEUE
+ if (dlsym(RTLD_DEFAULT, "kqueue") != 0) {
+ fdset_set_backend(&FDSET_KQUEUE);
+ return;
+ }
+#endif
+
+ /* Fallback: poll */
+#ifdef HAVE_POLL
+ if (dlsym(RTLD_DEFAULT, "poll") != 0) {
+ fdset_set_backend(&FDSET_POLL);
+ return;
+ }
+#endif
+
+ /* This shouldn't happen. */
+ fprintf(stderr, "fdset: fatal error - no valid fdset backend found\n");
+ return;
+}
diff --git a/src/common/fdset.h b/src/common/fdset.h
new file mode 100644
index 0000000..10196bf
--- /dev/null
+++ b/src/common/fdset.h
@@ -0,0 +1,196 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file fdset.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Wrapper for native I/O multiplexing.
+ *
+ * Selects best implementation according to config.
+ * - select()
+ * - poll() \todo
+ * - epoll()
+ * - kqueue()
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_FDSET_H_
+#define _KNOTD_FDSET_H_
+
+#include <stddef.h>
+
+/*! \brief Opaque pointer to implementation-specific fdset data. */
+typedef struct fdset_t fdset_t;
+
+/*! \brief Unified event types. */
+enum fdset_event_t {
+ OS_EV_READ = 1 << 0, /*!< Readable event. */
+ OS_EV_WRITE = 1 << 1, /*!< Writeable event. */
+ OS_EV_ERROR = 1 << 2 /*!< Error event. */
+};
+
+/*! \brief File descriptor set iterator. */
+typedef struct fdset_it_t {
+ int fd; /*!< Current file descriptor. */
+ int events; /*!< Returned events. */
+ size_t pos; /* Internal usage. */
+} fdset_it_t;
+
+/*!
+ * \brief File descriptor set implementation backend.
+ * \notice Functions documentation following.
+ * \internal
+ */
+struct fdset_backend_t
+{
+ fdset_t* (*fdset_new)();
+ int (*fdset_destroy)(fdset_t*);
+ int (*fdset_add)(fdset_t*, int, int);
+ int (*fdset_remove)(fdset_t*, int);
+ int (*fdset_wait)(fdset_t*);
+ int (*fdset_begin)(fdset_t*, fdset_it_t*);
+ int (*fdset_end)(fdset_t*, fdset_it_t*);
+ int (*fdset_next)(fdset_t*, fdset_it_t*);
+ const char* (*fdset_method)();
+};
+
+/*!
+ * \brief Selected backend.
+ * \internal
+ */
+extern struct fdset_backend_t _fdset_backend;
+
+/*!
+ * \brief Create new fdset.
+ *
+ * FDSET implementation depends on system.
+ *
+ * \retval Pointer to initialized FDSET structure if successful.
+ * \retval NULL on error.
+ */
+static inline fdset_t *fdset_new() {
+ return _fdset_backend.fdset_new();
+}
+
+/*!
+ * \brief Destroy FDSET.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on error.
+ */
+static inline int fdset_destroy(fdset_t * fdset) {
+ return _fdset_backend.fdset_destroy(fdset);
+}
+
+/*!
+ * \brief Add file descriptor to watched set.
+ *
+ * \param fdset Target set.
+ * \param fd Added file descriptor.
+ * \param events Mask of watched events.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+static inline int fdset_add(fdset_t *fdset, int fd, int events) {
+ return _fdset_backend.fdset_add(fdset, fd, events);
+}
+
+
+/*!
+ * \brief Remove file descriptor from watched set.
+ *
+ * \param fdset Target set.
+ * \param fd File descriptor to be removed.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+static inline int fdset_remove(fdset_t *fdset, int fd) {
+ return _fdset_backend.fdset_remove(fdset, fd);
+}
+
+/*!
+ * \brief Poll set for new events.
+ *
+ * \param fdset Target set.
+ *
+ * \retval Number of events if successful.
+ * \retval -1 on errors.
+ *
+ * \todo Timeout.
+ */
+static inline int fdset_wait(fdset_t *fdset) {
+ return _fdset_backend.fdset_wait(fdset);
+}
+
+/*!
+ * \brief Set event iterator to the beginning of last polled events.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+static inline int fdset_begin(fdset_t *fdset, fdset_it_t *it) {
+ return _fdset_backend.fdset_begin(fdset, it);
+}
+
+/*!
+ * \brief Set event iterator to the end of last polled events.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+static inline int fdset_end(fdset_t *fdset, fdset_it_t *it) {
+ return _fdset_backend.fdset_end(fdset, it);
+}
+
+/*!
+ * \brief Set event iterator to the next event.
+ *
+ * Event iterator fd will be set to -1 if next event doesn't exist.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+static inline int fdset_next(fdset_t *fdset, fdset_it_t *it) {
+ return _fdset_backend.fdset_next(fdset, it);
+}
+
+/*!
+ * \brief Returned name of underlying poll method.
+ *
+ * \retval Name if successful.
+ * \retval NULL if no method was loaded (shouldn't happen).
+ */
+static inline const char* fdset_method() {
+ return _fdset_backend.fdset_method();
+}
+
+#endif /* _KNOTD_FDSET_H_ */
+
+/*! @} */
diff --git a/src/common/fdset_epoll.c b/src/common/fdset_epoll.c
new file mode 100644
index 0000000..cb2e3e1
--- /dev/null
+++ b/src/common/fdset_epoll.c
@@ -0,0 +1,216 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_EPOLL_WAIT
+
+#include <sys/epoll.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "fdset_epoll.h"
+
+#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */
+#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */
+
+struct fdset_t {
+ int epfd;
+ struct epoll_event *events;
+ size_t nfds;
+ size_t reserved;
+ size_t polled;
+};
+
+fdset_t *fdset_epoll_new()
+{
+ fdset_t *set = malloc(sizeof(fdset_t));
+ if (!set) {
+ return 0;
+ }
+
+ /* Blank memory. */
+ memset(set, 0, sizeof(fdset_t));
+
+ /* Create epoll fd. */
+ set->epfd = epoll_create(OS_FDS_CHUNKSIZE);
+
+ return set;
+}
+
+int fdset_epoll_destroy(fdset_t * fdset)
+{
+ if(!fdset) {
+ return -1;
+ }
+
+ /* Teardown epoll. */
+ close(fdset->epfd);
+
+ /* OK if NULL. */
+ free(fdset->events);
+ free(fdset);
+ return 0;
+}
+
+int fdset_epoll_add(fdset_t *fdset, int fd, int events)
+{
+ if (!fdset || fd < 0 || events <= 0) {
+ return -1;
+ }
+
+ /* Realloc needed. */
+ if (fdset->nfds == fdset->reserved) {
+ const size_t chunk = OS_FDS_CHUNKSIZE;
+ const size_t nsize = (fdset->reserved + chunk) *
+ sizeof(struct epoll_event);
+ struct epoll_event *events_n = malloc(nsize);
+ if (!events_n) {
+ return -1;
+ }
+
+ /* Clear and copy old fdset data. */
+ memset(events_n, 0, nsize);
+ memcpy(events_n, fdset->events,
+ fdset->nfds * sizeof(struct epoll_event));
+ free(fdset->events);
+ fdset->events = events_n;
+ fdset->reserved += chunk;
+ }
+
+ /* Add to epoll set. */
+ struct epoll_event ev;
+ memset(&ev, 0, sizeof(struct epoll_event));
+ ev.events = EPOLLIN; /*! \todo MAP events. */
+ ev.data.fd = fd;
+ if (epoll_ctl(fdset->epfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
+ return -1;
+ }
+
+ ++fdset->nfds;
+ return 0;
+}
+
+int fdset_epoll_remove(fdset_t *fdset, int fd)
+{
+ if (!fdset || fd < 0) {
+ return -1;
+ }
+
+ /* Attempt to remove from set. */
+ struct epoll_event ev;
+ memset(&ev, 0, sizeof(struct epoll_event));
+ if (epoll_ctl(fdset->epfd, EPOLL_CTL_DEL, fd, &ev) < 0) {
+ return -1;
+ }
+
+ /* Overwrite current item. */
+ --fdset->nfds;
+
+ /*! \todo Return memory if overallocated (nfds is far lower than reserved). */
+ return 0;
+}
+
+int fdset_epoll_wait(fdset_t *fdset)
+{
+ if (!fdset || fdset->nfds < 1 || !fdset->events) {
+ return -1;
+ }
+
+ /* Poll new events. */
+ fdset->polled = 0;
+ int nfds = epoll_wait(fdset->epfd, fdset->events, fdset->nfds, -1);
+
+ /* Check. */
+ if (nfds < 0) {
+ return -1;
+ }
+
+ /* Events array is ordered from 0 to nfds. */
+ fdset->polled = nfds;
+ return nfds;
+}
+
+int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it) {
+ return -1;
+ }
+
+ /* Find first. */
+ it->pos = 0;
+ return fdset_next(fdset, it);
+}
+
+int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it || fdset->nfds < 1) {
+ return -1;
+ }
+
+ /* Check for polled events. */
+ if (fdset->polled < 1) {
+ it->fd = -1;
+ it->pos = 0;
+ return -1;
+ }
+
+ /* No end found, ends on the beginning. */
+ size_t nid = fdset->polled - 1;
+ it->fd = fdset->events[nid].data.fd;
+ it->pos = nid;
+ it->events = 0; /*! \todo Map events. */
+ return -1;
+}
+
+int fdset_epoll_next(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it || fdset->nfds < 1) {
+ return -1;
+ }
+
+ /* Check boundaries. */
+ if (it->pos >= fdset->polled) {
+ return -1;
+ }
+
+ /* Select next. */
+ size_t nid = it->pos++;
+ it->fd = fdset->events[nid].data.fd;
+ it->events = 0; /*! \todo Map events. */
+ return 0;
+}
+
+const char* fdset_epoll_method()
+{
+ return "epoll";
+}
+
+/* Package APIs. */
+struct fdset_backend_t FDSET_EPOLL = {
+ .fdset_new = fdset_epoll_new,
+ .fdset_destroy = fdset_epoll_destroy,
+ .fdset_add = fdset_epoll_add,
+ .fdset_remove = fdset_epoll_remove,
+ .fdset_wait = fdset_epoll_wait,
+ .fdset_begin = fdset_epoll_begin,
+ .fdset_end = fdset_epoll_end,
+ .fdset_next = fdset_epoll_next,
+ .fdset_method = fdset_epoll_method
+};
+
+#endif
diff --git a/src/common/fdset_epoll.h b/src/common/fdset_epoll.h
new file mode 100644
index 0000000..551394d
--- /dev/null
+++ b/src/common/fdset_epoll.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file fdset_epoll.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Wrapper for epoll I/O multiplexing.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_FDSET_EPOLL_H_
+#define _KNOTD_FDSET_EPOLL_H_
+
+#include "fdset.h"
+
+/*!
+ * \brief Create new fdset.
+ *
+ * Linux epoll() backend.
+ *
+ * \retval Pointer to initialized FDSET structure if successful.
+ * \retval NULL on error.
+ */
+fdset_t *fdset_epoll_new();
+
+/*!
+ * \brief Destroy FDSET.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on error.
+ */
+int fdset_epoll_destroy(fdset_t * fdset);
+
+/*!
+ * \brief Add file descriptor to watched set.
+ *
+ * \param fdset Target set.
+ * \param fd Added file descriptor.
+ * \param events Mask of watched events.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_epoll_add(fdset_t *fdset, int fd, int events);
+
+/*!
+ * \brief Remove file descriptor from watched set.
+ *
+ * \param fdset Target set.
+ * \param fd File descriptor to be removed.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_epoll_remove(fdset_t *fdset, int fd);
+
+/*!
+ * \brief Poll set for new events.
+ *
+ * \param fdset Target set.
+ *
+ * \retval Number of events if successful.
+ * \retval -1 on errors.
+ *
+ * \todo Timeout.
+ */
+int fdset_epoll_wait(fdset_t *fdset);
+
+/*!
+ * \brief Set event iterator to the beginning of last polled events.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Set event iterator to the end of last polled events.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Set event iterator to the next event.
+ *
+ * Event iterator fd will be set to -1 if next event doesn't exist.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_epoll_next(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Returned name of epoll method.
+ *
+ * \retval Name if successful.
+ * \retval NULL if no method was loaded (shouldn't happen).
+ */
+const char* fdset_epoll_method();
+
+/*! \brief Exported API. */
+extern struct fdset_backend_t FDSET_EPOLL;
+
+#endif /* _KNOTD_FDSET_EPOLL_H_ */
+
+/*! @} */
diff --git a/src/common/fdset_kqueue.c b/src/common/fdset_kqueue.c
new file mode 100644
index 0000000..c7199ae
--- /dev/null
+++ b/src/common/fdset_kqueue.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_KQUEUE
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/event.h>
+#include <sys/time.h>
+
+#include "fdset_kqueue.h"
+
+#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */
+#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */
+
+struct fdset_t {
+ int kq;
+ struct kevent *events;
+ struct kevent *revents;
+ size_t nfds;
+ size_t reserved;
+ size_t polled;
+};
+
+fdset_t *fdset_kqueue_new()
+{
+ fdset_t *set = malloc(sizeof(fdset_t));
+ if (!set) {
+ return 0;
+ }
+
+ /* Blank memory. */
+ memset(set, 0, sizeof(fdset_t));
+
+ /* Create kqueue fd. */
+ set->kq = kqueue();
+ if (set->kq < 0) {
+ free(set);
+ set = 0;
+ }
+
+ return set;
+}
+
+int fdset_kqueue_destroy(fdset_t * fdset)
+{
+ if(!fdset) {
+ return -1;
+ }
+
+ /* Teardown kqueue. */
+ close(fdset->kq);
+
+ /* OK if NULL. */
+ free(fdset->revents);
+ free(fdset->events);
+ free(fdset);
+ return 0;
+}
+
+int fdset_kqueue_realloc(void **old, size_t oldsize, size_t nsize)
+{
+ void *nmem = malloc(nsize);
+ if (!nmem) {
+ return -1;
+ }
+
+ /* Clear and copy old fdset data. */
+ memset(nmem, 0, nsize);
+ if (oldsize > 0) {
+ memcpy(nmem, *old, oldsize);
+ free(*old);
+ }
+
+ *old = nmem;
+ return 0;
+}
+
+int fdset_kqueue_add(fdset_t *fdset, int fd, int events)
+{
+ if (!fdset || fd < 0 || events <= 0) {
+ return -1;
+ }
+
+ /* Realloc needed. */
+ if (fdset->nfds == fdset->reserved) {
+ const size_t chunk = OS_FDS_CHUNKSIZE;
+ const size_t nsize = (fdset->reserved + chunk) *
+ sizeof(struct kevent);
+ const size_t oldsize = fdset->nfds * sizeof(struct kevent);
+
+ if (fdset_kqueue_realloc(&fdset->events, oldsize, nsize) < 0) {
+ return -1;
+ }
+
+ if (fdset_kqueue_realloc(&fdset->revents, oldsize, nsize) < 0) {
+ return -1;
+ }
+
+ }
+
+ /* Add to kqueue set. */
+ int evfilt = EVFILT_READ; /*! \todo Map events. */
+ EV_SET(&fdset->events[fdset->nfds], fd, evfilt,
+ EV_ADD|EV_ENABLE, 0, 0, 0);
+
+ ++fdset->nfds;
+ return 0;
+}
+
+int fdset_kqueue_remove(fdset_t *fdset, int fd)
+{
+ if (!fdset || fd < 0) {
+ return -1;
+ }
+
+ /* Find in set. */
+ int pos = -1;
+ for (int i = 0; i < fdset->nfds; ++i) {
+ if (fdset->events[i].ident == fd) {
+ pos = i;
+ break;
+ }
+ }
+
+ if (pos < 0) {
+ return -1;
+ }
+
+ /* Remove filters. */
+ EV_SET(&fdset->events[pos], fd, EVFILT_READ,
+ EV_DISABLE|EV_DELETE, 0, 0, 0);
+
+ /* Attempt to remove from set. */
+ size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct kevent);
+ memmove(fdset->events + pos, fdset->events + (pos + 1), remaining);
+
+ /* Overwrite current item. */
+ --fdset->nfds;
+
+ /*! \todo Return memory if overallocated (nfds is far lower than reserved). */
+ return 0;
+}
+
+int fdset_kqueue_wait(fdset_t *fdset)
+{
+ if (!fdset || fdset->nfds < 1 || !fdset->events) {
+ return -1;
+ }
+
+ /* Poll new events. */
+ fdset->polled = 0;
+ int nfds = kevent(fdset->kq, fdset->events, fdset->nfds,
+ fdset->revents, fdset->nfds, 0);
+
+ /* Check. */
+ if (nfds < 0) {
+ return -1;
+ }
+
+ /* Events array is ordered from 0 to nfds. */
+ fdset->polled = nfds;
+ return nfds;
+}
+
+int fdset_kqueue_begin(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it) {
+ return -1;
+ }
+
+ /* Find first. */
+ it->pos = 0;
+ return fdset_next(fdset, it);
+}
+
+int fdset_kqueue_end(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it || fdset->nfds < 1) {
+ return -1;
+ }
+
+ /* Check for polled events. */
+ if (fdset->polled < 1) {
+ it->fd = -1;
+ it->pos = 0;
+ return -1;
+ }
+
+ /* No end found, ends on the beginning. */
+ size_t nid = fdset->polled - 1;
+ it->fd = fdset->revents[nid].ident;
+ it->pos = nid;
+ it->events = 0; /*! \todo Map events. */
+ return -1;
+}
+
+int fdset_kqueue_next(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it || fdset->nfds < 1) {
+ return -1;
+ }
+
+ /* Check boundaries. */
+ if (it->pos >= fdset->polled) {
+ return -1;
+ }
+
+ /* Select next. */
+ size_t nid = it->pos++;
+ it->fd = fdset->revents[nid].ident;
+ it->events = 0; /*! \todo Map events. */
+ return 0;
+}
+
+const char* fdset_kqueue_method()
+{
+ return "kqueue";
+}
+
+/* Package APIs. */
+struct fdset_backend_t FDSET_KQUEUE = {
+ .fdset_new = fdset_kqueue_new,
+ .fdset_destroy = fdset_kqueue_destroy,
+ .fdset_add = fdset_kqueue_add,
+ .fdset_remove = fdset_kqueue_remove,
+ .fdset_wait = fdset_kqueue_wait,
+ .fdset_begin = fdset_kqueue_begin,
+ .fdset_end = fdset_kqueue_end,
+ .fdset_next = fdset_kqueue_next,
+ .fdset_method = fdset_kqueue_method
+};
+
+#endif
diff --git a/src/common/fdset_kqueue.h b/src/common/fdset_kqueue.h
new file mode 100644
index 0000000..f64482f
--- /dev/null
+++ b/src/common/fdset_kqueue.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file fdset_kqueue.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Wrapper for kqueue I/O multiplexing.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_FDSET_KQUEUE_H_
+#define _KNOTD_FDSET_KQUEUE_H_
+
+#include "fdset.h"
+
+/*!
+ * \brief Create new fdset.
+ *
+ * BSD kqueue() backend.
+ *
+ * \retval Pointer to initialized FDSET structure if successful.
+ * \retval NULL on error.
+ */
+fdset_t *fdset_kqueue_new();
+
+/*!
+ * \brief Destroy FDSET.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on error.
+ */
+int fdset_kqueue_destroy(fdset_t * fdset);
+
+/*!
+ * \brief Add file descriptor to watched set.
+ *
+ * \param fdset Target set.
+ * \param fd Added file descriptor.
+ * \param events Mask of watched events.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_kqueue_add(fdset_t *fdset, int fd, int events);
+
+/*!
+ * \brief Remove file descriptor from watched set.
+ *
+ * \param fdset Target set.
+ * \param fd File descriptor to be removed.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_kqueue_remove(fdset_t *fdset, int fd);
+
+/*!
+ * \brief Poll set for new events.
+ *
+ * \param fdset Target set.
+ *
+ * \retval Number of events if successful.
+ * \retval -1 on errors.
+ *
+ * \todo Timeout.
+ */
+int fdset_kqueue_wait(fdset_t *fdset);
+
+/*!
+ * \brief Set event iterator to the beginning of last polled events.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_kqueue_begin(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Set event iterator to the end of last polled events.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_kqueue_end(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Set event iterator to the next event.
+ *
+ * Event iterator fd will be set to -1 if next event doesn't exist.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_kqueue_next(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Returned name of kqueue method.
+ *
+ * \retval Name if successful.
+ * \retval NULL if no method was loaded (shouldn't happen).
+ */
+const char* fdset_kqueue_method();
+
+/*! \brief Exported API. */
+extern struct fdset_backend_t FDSET_KQUEUE;
+
+#endif /* _KNOTD_FDSET_KQUEUE_H_ */
+
+/*! @} */
diff --git a/src/common/fdset_poll.c b/src/common/fdset_poll.c
new file mode 100644
index 0000000..8682eaf
--- /dev/null
+++ b/src/common/fdset_poll.c
@@ -0,0 +1,230 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_POLL
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <stddef.h>
+
+#include "common/fdset_poll.h"
+
+#define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */
+#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */
+
+struct fdset_t {
+ struct pollfd *fds;
+ nfds_t nfds;
+ size_t reserved;
+ size_t polled;
+ size_t begin;
+};
+
+fdset_t *fdset_poll_new()
+{
+ fdset_t *set = malloc(sizeof(fdset_t));
+ if (!set) {
+ return 0;
+ }
+
+ /* Blank memory. */
+ memset(set, 0, sizeof(fdset_t));
+ return set;
+}
+
+int fdset_poll_destroy(fdset_t * fdset)
+{
+ if(!fdset) {
+ return -1;
+ }
+
+ /*! \todo No teardown required I guess. */
+
+ /* OK if NULL. */
+ free(fdset->fds);
+ free(fdset);
+ return 0;
+}
+
+int fdset_poll_add(fdset_t *fdset, int fd, int events)
+{
+ if (!fdset || fd < 0 || events <= 0) {
+ return -1;
+ }
+
+ /* Realloc needed. */
+ if (fdset->nfds == fdset->reserved) {
+ const size_t chunk = OS_FDS_CHUNKSIZE;
+ const size_t nsize = sizeof(struct pollfd) * (fdset->reserved + chunk);
+ struct pollfd *fds_n = malloc(nsize);
+ if (!fds_n) {
+ return -1;
+ }
+
+ /* Clear and copy old fdset data. */
+ memset(fds_n, 0, nsize);
+ memcpy(fds_n, fdset->fds, fdset->nfds * sizeof(struct pollfd));
+ free(fdset->fds);
+ fdset->fds = fds_n;
+ fdset->reserved += chunk;
+ }
+
+ /* Append. */
+ int nid = fdset->nfds++;
+ fdset->fds[nid].fd = fd;
+ fdset->fds[nid].events = POLLIN; /*! \todo Map events to POLL events. */
+ return 0;
+}
+
+int fdset_poll_remove(fdset_t *fdset, int fd)
+{
+ if (!fdset || fd < 0) {
+ return -1;
+ }
+
+ /* Find file descriptor. */
+ unsigned found = 0;
+ size_t pos = 0;
+ for (size_t i = 0; i < fdset->nfds; ++i) {
+ if (fdset->fds[i].fd == fd) {
+ found = 1;
+ pos = i;
+ break;
+ }
+ }
+
+ /* Check. */
+ if (!found) {
+ return -1;
+ }
+
+ /* Overwrite current item. */
+ size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct pollfd);
+ memmove(fdset->fds + pos, fdset->fds + (pos + 1), remaining);
+ --fdset->nfds;
+
+ /*! \todo Return memory if overallocated (nfds is far lower than reserved). */
+ /*! \todo Maybe >64 free chunks is excess? */
+ return 0;
+}
+
+int fdset_poll_wait(fdset_t *fdset)
+{
+ if (!fdset || fdset->nfds < 1 || !fdset->fds) {
+ return -1;
+ }
+
+ /* Initialize pointers. */
+ fdset->polled = 0;
+ fdset->begin = 0;
+
+ /* Poll for events. */
+ int ret = poll(fdset->fds, fdset->nfds, -1);
+ if (ret < 0) {
+ return -1;
+ }
+
+ /* Set pointers for iterating. */
+ fdset->polled = ret;
+ fdset->begin = 0;
+ return ret;
+}
+
+int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it) {
+ return -1;
+ }
+
+ /* Find first. */
+ it->pos = 0;
+ return fdset_next(fdset, it);
+}
+
+int fdset_poll_end(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it || fdset->nfds < 1) {
+ return -1;
+ }
+
+ /* Check for polled events. */
+ if (fdset->polled < 1) {
+ it->fd = -1;
+ it->pos = 0;
+ return -1;
+ }
+
+ /* Trace last matching item from the end. */
+ struct pollfd* pfd = fdset->fds + fdset->nfds - 1;
+ while (pfd != fdset->fds) {
+ if (pfd->events & pfd->revents) {
+ it->fd = pfd->fd;
+ it->pos = pfd - fdset->fds;
+ return 0;
+ }
+ }
+
+ /* No end found, ends on the beginning. */
+ it->fd = -1;
+ it->pos = 0;
+ return -1;
+}
+
+int fdset_poll_next(fdset_t *fdset, fdset_it_t *it)
+{
+ if (!fdset || !it || fdset->nfds < 1) {
+ return -1;
+ }
+
+ /* Find next with matching flags. */
+ for (; it->pos < fdset->nfds; ++it->pos) {
+ struct pollfd* pfd = fdset->fds + it->pos;
+ if (pfd->events & pfd->revents) {
+ it->fd = pfd->fd;
+ it->events = pfd->revents; /*! \todo MAP events. */
+ ++it->pos; /* Next will start after current. */
+ return 0;
+ }
+ }
+
+ /* No matching event found. */
+ it->fd = -1;
+ it->pos = 0;
+ return -1;
+}
+
+const char* fdset_poll_method()
+{
+ return "poll";
+}
+
+/* Package APIs. */
+struct fdset_backend_t FDSET_POLL = {
+ .fdset_new = fdset_poll_new,
+ .fdset_destroy = fdset_poll_destroy,
+ .fdset_add = fdset_poll_add,
+ .fdset_remove = fdset_poll_remove,
+ .fdset_wait = fdset_poll_wait,
+ .fdset_begin = fdset_poll_begin,
+ .fdset_end = fdset_poll_end,
+ .fdset_next = fdset_poll_next,
+ .fdset_method = fdset_poll_method
+};
+
+#endif
diff --git a/src/common/fdset_poll.h b/src/common/fdset_poll.h
new file mode 100644
index 0000000..d72b5bb
--- /dev/null
+++ b/src/common/fdset_poll.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file fdset_poll.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Wrapper for poll I/O multiplexing.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_FDSET_POLL_H_
+#define _KNOTD_FDSET_POLL_H_
+
+#include "fdset.h"
+
+/*!
+ * \brief Create new fdset.
+ *
+ * POSIX poll() backend.
+ *
+ * \retval Pointer to initialized FDSET structure if successful.
+ * \retval NULL on error.
+ */
+fdset_t *fdset_poll_new();
+
+/*!
+ * \brief Destroy FDSET.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on error.
+ */
+int fdset_poll_destroy(fdset_t * fdset);
+
+/*!
+ * \brief Add file descriptor to watched set.
+ *
+ * \param fdset Target set.
+ * \param fd Added file descriptor.
+ * \param events Mask of watched events.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_poll_add(fdset_t *fdset, int fd, int events);
+
+/*!
+ * \brief Remove file descriptor from watched set.
+ *
+ * \param fdset Target set.
+ * \param fd File descriptor to be removed.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_poll_remove(fdset_t *fdset, int fd);
+
+/*!
+ * \brief Poll set for new events.
+ *
+ * \param fdset Target set.
+ *
+ * \retval Number of events if successful.
+ * \retval -1 on errors.
+ *
+ * \todo Timeout.
+ */
+int fdset_poll_wait(fdset_t *fdset);
+
+/*!
+ * \brief Set event iterator to the beginning of last polled events.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Set event iterator to the end of last polled events.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_poll_end(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Set event iterator to the next event.
+ *
+ * Event iterator fd will be set to -1 if next event doesn't exist.
+ *
+ * \param fdset Target set.
+ * \param it Event iterator.
+ *
+ * \retval 0 if successful.
+ * \retval -1 on errors.
+ */
+int fdset_poll_next(fdset_t *fdset, fdset_it_t *it);
+
+/*!
+ * \brief Returned name of poll method.
+ *
+ * \retval Name if successful.
+ * \retval NULL if no method was loaded (shouldn't happen).
+ */
+const char* fdset_poll_method();
+
+/*! \brief Exported API. */
+extern struct fdset_backend_t FDSET_POLL;
+
+#endif /* _KNOTD_FDSET_POLL_H_ */
+
+/*! @} */
diff --git a/src/common/general-tree.c b/src/common/general-tree.c
new file mode 100644
index 0000000..202b31a
--- /dev/null
+++ b/src/common/general-tree.c
@@ -0,0 +1,215 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "common/general-tree.h"
+#include "common/errors.h"
+
+MOD_TREE_DEFINE(general_tree_node, avl);
+
+static void gen_rem_func(struct general_tree_node *n1)
+{
+ free(n1);
+}
+
+general_tree_t *gen_tree_new(int (*comp_func)(void *, void *))
+{
+ general_tree_t *ret = malloc(sizeof(general_tree_t));
+ if (ret == NULL) {
+ return NULL;
+ }
+ ret->tree = malloc(sizeof(general_avl_tree_t));
+ if (ret->tree == NULL) {
+ free(ret);
+ return NULL;
+ }
+ MOD_TREE_INIT(ret->tree, comp_func);
+ return ret;
+}
+
+int gen_tree_add(general_tree_t *tree,
+ void *node, int (*mrg_func)(void **n1, void **n2))
+{
+ struct general_tree_node *tree_node =
+ malloc(sizeof(struct general_tree_node));
+ if (tree_node == NULL) {
+ return -1;
+ }
+ memset(tree_node, 0, sizeof(struct general_tree_node));
+ tree_node->data = node;
+ int merged = 0;
+ MOD_TREE_INSERT(tree->tree, general_tree_node, avl,
+ tree_node, mrg_func, &merged);
+ if (merged) {
+ free(tree_node);
+ }
+ return merged;
+}
+
+void gen_tree_remove(general_tree_t *tree,
+ void *what)
+{
+ struct general_tree_node tree_node;
+ tree_node.data = what;
+ MOD_TREE_REMOVE(tree->tree, general_tree_node, avl, &tree_node,
+ gen_rem_func);
+}
+
+void *gen_tree_find(general_tree_t *tree,
+ void *what)
+{
+ struct general_tree_node tree_node;
+ tree_node.data = what;
+ struct general_tree_node *found_node =
+ MOD_TREE_FIND(tree->tree, general_tree_node, avl, &tree_node);
+ if (found_node) {
+ return found_node->data;
+ } else {
+ return NULL;
+ }
+}
+
+int gen_tree_find_less_or_equal(general_tree_t *tree,
+ void *what,
+ void **found)
+{
+ if (tree == NULL || tree->tree == NULL) {
+ return -1;
+ }
+
+ /* Check if tree is empty. */
+ if (tree->tree->th_root == NULL) {
+ *found = NULL;
+ return 0;
+ }
+
+ struct general_tree_node *f = NULL, *prev = NULL;
+ struct general_tree_node tree_node;
+ tree_node.data = what;
+ int exact_match =
+ MOD_TREE_FIND_LESS_EQUAL(tree->tree, general_tree_node, avl,
+ &tree_node, &f, &prev);
+ if (exact_match < 0) {
+ *found = NULL;
+ exact_match = 0;
+ } else if (exact_match == 0) {
+ assert(prev != NULL);
+ *found = prev->data;
+ } else {
+ assert(f != NULL);
+ *found = f->data;
+ }
+// *found = (exact_match > 0) ? f->data : prev->data;
+ return exact_match;
+}
+
+void gen_tree_apply_inorder(general_tree_t *tree,
+ void (*app_func)
+ (void *node, void *data), void *data)
+{
+ MOD_TREE_FORWARD_APPLY(tree->tree, general_tree_node, avl,
+ app_func, data);
+}
+
+void gen_tree_destroy(general_tree_t **tree,
+ void (*dest_func)(void *node, void *data), void *data)
+{
+// gen_tree_apply_inorder(*tree, print_node, NULL);
+ MOD_TREE_DESTROY((*tree)->tree, general_tree_node, avl, dest_func,
+ gen_rem_func, data);
+ free((*tree)->tree);
+ free(*tree);
+ *tree = NULL;
+}
+
+void gen_tree_clear(general_tree_t *tree)
+{
+ MOD_TREE_DESTROY(tree->tree, general_tree_node, avl, NULL,
+ gen_rem_func, NULL);
+}
+
+//static void add_node_to_tree(void *n, void *data)
+//{
+// general_tree_t *tree = (general_tree_t *)data;
+// gen_tree_add(tree, n, NULL);
+//}
+
+static int gen_tree_copy_node(const struct general_tree_node *from,
+ struct general_tree_node **to)
+{
+ if (from == NULL) {
+ return 0;
+ }
+
+ *to = malloc(sizeof(struct general_tree_node));
+ if (*to == NULL) {
+ return -1;
+ }
+ memset(*to, 0, sizeof(struct general_tree_node));
+
+ (*to)->data = from->data;
+ (*to)->avl.avl_height = from->avl.avl_height;
+
+ int ret = gen_tree_copy_node(from->avl.avl_left,
+ &(*to)->avl.avl_left);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = gen_tree_copy_node(from->avl.avl_right,
+ &(*to)->avl.avl_right);
+ if (ret != 0) {
+ /*! \todo Partially cleaunp tree! */
+ (*to)->avl.avl_left = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+general_tree_t *gen_tree_shallow_copy(general_tree_t *tree)
+{
+ general_tree_t *new_tree = malloc(sizeof(general_tree_t));
+ if (new_tree == NULL) {
+ return NULL;
+ }
+ new_tree->tree = malloc(sizeof(general_avl_tree_t));
+ if (new_tree->tree == NULL) {
+ free(new_tree);
+ return NULL;
+ }
+
+ MOD_TREE_INIT(new_tree->tree, tree->tree->th_cmp);
+ assert(new_tree->tree->th_cmp == tree->tree->th_cmp);
+
+// gen_tree_apply_inorder(tree, add_node_to_tree, new_tree);
+
+ if (gen_tree_copy_node(tree->tree->th_root,
+ &new_tree->tree->th_root) != 0) {
+ return NULL;
+ }
+
+ /* CLEANUP */
+// gen_tree_apply_inorder(tree, print_node, NULL);
+// printf("--------------------------\n");
+// gen_tree_apply_inorder(new_tree, print_node, NULL);
+
+ return new_tree;
+}
+
diff --git a/src/common/general-tree.h b/src/common/general-tree.h
new file mode 100644
index 0000000..552638a
--- /dev/null
+++ b/src/common/general-tree.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_COMMON_GENERAL_TREE_H_
+#define _KNOTD_COMMON_GENERAL_TREE_H_
+
+#include "common/modified_tree.h"
+
+typedef MOD_TREE_HEAD(tree, general_tree_node) general_avl_tree_t;
+
+/* Define tree with void * nodes */
+struct general_tree_node {
+ MOD_TREE_ENTRY(general_tree_node) avl;
+// int (*cmp_func)(void *n1,
+// void *n2);
+// int (*mrg_func)(void **n1,
+// void **n2);
+// void (*app_func)(void *n,
+// void *data);
+ void *data;
+};
+
+struct general_tree {
+// int (*cmp_func)(void *n1,
+// void *n2);
+// int (*mrg_func)(void **n1,
+// void **n2);
+ general_avl_tree_t *tree;
+};
+
+typedef struct general_tree general_tree_t;
+
+general_tree_t *gen_tree_new(int (*cmp_func)(void *p1, void *p2));
+
+int gen_tree_add(general_tree_t *tree,
+ void *node,
+ int (*mrg_func)(void **n1, void **n2));
+
+void *gen_tree_find(general_tree_t *tree,
+ void *what);
+
+void gen_tree_remove(general_tree_t *tree,
+ void *what);
+
+void gen_tree_apply_inorder(general_tree_t *tree,
+ void (*app_func)(void *node, void *data),
+ void *data);
+
+void gen_tree_destroy(general_tree_t **tree,
+ void (*dest_func)(void *node, void *data), void *data);
+
+void gen_tree_clear(general_tree_t *tree);
+
+int gen_tree_find_less_or_equal(general_tree_t *tree,
+ void *what,
+ void **found);
+
+general_tree_t *gen_tree_shallow_copy(general_tree_t *tree);
+
+#endif // _KNOTD_COMMON_GENERAL_TREE_H_
diff --git a/src/common/latency.c b/src/common/latency.c
new file mode 100644
index 0000000..a563f58
--- /dev/null
+++ b/src/common/latency.c
@@ -0,0 +1,197 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef PROF_LATENCY
+
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+
+
+/*! \brief Profiler statistics. */
+typedef struct pstat_t {
+ double M; /*!< \brief Mean value. */
+ unsigned long min, max; /*!< \brief Minimum, maximum. */
+ unsigned long total; /*!< \brief Total profiled time. */
+ unsigned long count; /*!< \brief Number of profiled calls. */
+} pstat_t;
+
+/*! \brief Function call profile. */
+typedef struct profile_t {
+ const char* call;
+ pstat_t stat;
+} profile_t;
+
+/*! \brief Observed function call codes. */
+enum pcall_code_t {
+ PF_RECVFROM = 0,
+ PF_SENDTO,
+ PF_PTHREAD_MUTEX_LOCK,
+ PF_PTHREAD_MUTEX_UNLOCK,
+ PF_CALL_SIZE
+} pcall_code_t;
+
+/*! \brief Table of observed function calls. */
+static profile_t table[] = {
+ { "recvfrom", {0} },
+ { "sendto", {0} },
+ { "pthread_mutex_lock", {0} },
+ { "pthread_mutex_unlock", {0} },
+ { "NULL", {0} }
+};
+
+
+/*! \brief Add value to statistics. */
+static inline void add_stat(pstat_t *stat, unsigned long val) {
+
+ if (val < stat->min) {
+ stat->min = val;
+ }
+ if (val > stat->max) {
+ stat->max = val;
+ }
+
+ stat->total += val;
+
+ double Mprev = stat->M, M = stat->M;
+ M += (val - M)/((double)stat->count + 1);
+ stat->M = M;
+ //S += (val - M)*(x[i] - Mprev);
+
+ ++stat->count;
+}
+
+/*! \brief Call profiler table initialization (automatically called on load). */
+void __attribute__ ((constructor)) profiler_init()
+{
+ for (int i = 0; i < PF_CALL_SIZE; ++i) {
+ pstat_t* stat = &table[i].stat;
+ stat->M = 0;
+ stat->max = 0;
+ stat->min = (unsigned long)~0;
+ stat->total = 0;
+ stat->count = 0;
+ }
+}
+
+/*! \brief Call profiler table evaluation (automatically called on exit). */
+void __attribute__ ((destructor)) profiler_deinit()
+{
+
+ /* Get resource usage. */
+ struct rusage usage;
+ if (getrusage(RUSAGE_SELF, &usage) < 0) {
+ memset(&usage, 0, sizeof(struct rusage));
+ }
+
+ fprintf(stderr, "\nStatistics:");
+ fprintf(stderr, "\n==================\n");
+
+ fprintf(stderr, "User time: %.03lf ms\nSystem time: %.03lf ms\n",
+ usage.ru_utime.tv_sec * (double) 1000.0
+ + usage.ru_utime.tv_usec / (double)1000.0,
+ usage.ru_stime.tv_sec * (double) 1000.0
+ + usage.ru_stime.tv_usec / (double)1000.0);
+ fprintf(stderr, "Voluntary context switches: %lu\nInvoluntary context switches: %lu\n",
+ usage.ru_nvcsw,
+ usage.ru_nivcsw);
+ fprintf(stderr, "==================\n");
+ fprintf(stderr, "\n");
+
+ /* Callers statistics. */
+ for (int i = 0; i < PF_CALL_SIZE; ++i) {
+ pstat_t* stat = &table[i].stat;
+ fprintf(stderr, "%s: M=%lf min=%lu,max=%lu (total=%lu, %lu times) (usec)\n",
+ table[i].call, stat->M, stat->min, stat->max, stat->total,
+ stat->count);
+ }
+
+}
+
+ssize_t pf_recvfrom(int socket, void *buf, size_t len, int flags,
+ struct sockaddr *from, socklen_t *fromlen,
+ const char* caller, const char* file, int line)
+{
+ unsigned long elapsed = 0;
+ int ret = 0;
+ perf_begin();
+ ret = recvfrom(socket, buf, len, flags, from, fromlen);
+ perf_end(elapsed);
+
+ /* Discard wakeup delays, count statistics otherwise. */
+ if (elapsed < 200000) {
+ add_stat(&table[PF_RECVFROM].stat, elapsed);
+ }
+ return ret;
+}
+
+ssize_t pf_sendto(int socket, const void *buf, size_t len, int flags,
+ const struct sockaddr *to, socklen_t tolen,
+ const char* caller, const char* file, int line)
+{
+ unsigned long elapsed = 0;
+ int ret = 0;
+ perf_begin();
+ ret = sendto(socket, buf, len, flags, to, tolen);
+ perf_end(elapsed);
+
+ /* Discard wakeup delays, count statistics otherwise. */
+ if (elapsed < 200000) {
+ add_stat(&table[PF_SENDTO].stat, elapsed);
+ }
+ return ret;
+}
+
+/* Pthreads */
+int pf_pthread_mutex_lock(pthread_mutex_t *mutex,
+ const char* caller, const char* file, int line)
+{
+ unsigned long elapsed = 0;
+ int ret = 0;
+ perf_begin();
+ ret = pthread_mutex_lock(mutex);
+ perf_end(elapsed);
+
+ /* Discard wakeup delays, count statistics otherwise. */
+ if (elapsed < 200000) {
+ add_stat(&table[PF_PTHREAD_MUTEX_LOCK].stat, elapsed);
+ }
+
+ return ret;
+}
+
+int pf_pthread_mutex_unlock(pthread_mutex_t *mutex,
+ const char* caller, const char* file, int line)
+{
+ unsigned long elapsed = 0;
+ int ret = 0;
+ perf_begin();
+ ret = pthread_mutex_unlock(mutex);
+ perf_end(elapsed);
+
+ /* Discard wakeup delays, count statistics otherwise. */
+ if (elapsed < 200000) {
+ add_stat(&table[PF_PTHREAD_MUTEX_UNLOCK].stat, elapsed);
+ }
+
+ return ret;
+}
+
+#endif // PROF_LATENCY
diff --git a/src/common/latency.h b/src/common/latency.h
new file mode 100644
index 0000000..d965c56
--- /dev/null
+++ b/src/common/latency.h
@@ -0,0 +1,115 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file latency.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Utilities for latency profiling.
+ *
+ * Selected calls latency profiler is enabled with PROF_LATENCY define.
+ * You can roughly profile own code with perf_begin() and perf_end() macros.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_LATENCY_H_
+#define _KNOTD_COMMON_LATENCY_H_
+
+/* Optional. */
+#ifdef PROF_LATENCY
+
+/* Do not include from latency.c */
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <pthread.h>
+
+/* Profiler tools */
+
+/*! \brief Time profile begin macro. */
+#define perf_begin() \
+do { \
+ struct timeval __begin; \
+ gettimeofday(&__begin, 0)
+
+/*! \brief Time profile end macro
+ * \param d Will contain the number of microseconds passed from perf_begin().
+ */
+#define perf_end(d) \
+ struct timeval __end; \
+ gettimeofday(&__end, 0); \
+ unsigned long __us = (__end.tv_sec - __begin.tv_sec) * 1000L * 1000L; \
+ __us += (__end.tv_usec - __begin.tv_usec); \
+ (d) = __us; \
+} while(0)
+
+/* Prototypes. */
+
+/*! \brief Profiled recvfrom(). */
+ssize_t pf_recvfrom(int socket, void *buf, size_t len, int flags,
+ struct sockaddr *from, socklen_t *fromlen,
+ const char* caller, const char* file, int line);
+
+/*! \brief Profiled sendto(). */
+ssize_t pf_sendto(int socket, const void *buf, size_t len, int flags,
+ const struct sockaddr *to, socklen_t tolen,
+ const char* caller, const char* file, int line);
+
+/*! \brief Profiled pthread_mutex_lock(). */
+int pf_pthread_mutex_lock(pthread_mutex_t *mutex,
+ const char* caller, const char* file, int line);
+
+/*! \brief Profiled pthread_mutex_unlock(). */
+int pf_pthread_mutex_unlock(pthread_mutex_t *mutex,
+ const char* caller, const char* file, int line);
+
+/*
+ * Sockets.
+ */
+
+/*! \brief Rerouted recvfrom(). */
+#define recvfrom(s, buf, len, flags, from, fromlen) \
+ pf_recvfrom((s), (buf), (len), (flags), (from), (fromlen), \
+ __FUNCTION__, __FILE__, __LINE__)
+
+/*! \brief Rerouted sendto(). */
+#define sendto(s, buf, len, flags, to, tolen) \
+ pf_sendto((s), (buf), (len), (flags), (to), (tolen), \
+ __FUNCTION__, __FILE__, __LINE__)
+
+/*
+ * Pthreads.
+ */
+
+/*! \brief Rerouted pthread_mutex_lock(). */
+#define pthread_mutex_lock(m) \
+ pf_pthread_mutex_lock(m, __FUNCTION__, __FILE__, __LINE__)
+
+/*! \brief Rerouted pthread_mutex_unlock(). */
+#define pthread_mutex_unlock(m) \
+ pf_pthread_mutex_unlock(m, __FUNCTION__, __FILE__, __LINE__)
+
+#else // PROF_LATENCY
+
+/* Profiler tools */
+#define perf_begin()
+#define perf_end(d)
+
+#endif // PROF_LATENCY
+#endif // _KNOTD_COMMON_LATENCY_H_
+
+/*! @} */
diff --git a/src/common/libtap/README b/src/common/libtap/README
new file mode 100644
index 0000000..d57b81d
--- /dev/null
+++ b/src/common/libtap/README
@@ -0,0 +1,231 @@
+NAME
+====
+
+libtap - Write tests in C
+
+SYNOPSIS
+========
+
+ #include <tap.h>
+
+ int foo () {return 3;}
+ char *bar () {return "fnord";}
+
+ int main () {
+ plan(5);
+ ok(foo() == 3);
+ is(bar(), "eek");
+ ok(foo() <= 8732, "foo <= %d", 8732);
+ like(bar(), "f(yes|no)r*[a-f]$", "is like");
+ cmp_ok(foo(), ">=", 10, "foo is greater than ten");
+ return exit_status();
+ }
+
+results in:
+
+ 1..5
+ ok 1
+ not ok 2
+ # Failed test at synopsis.c line 9.
+ # got: 'fnord'
+ # expected: 'eek'
+ ok 3 - foo <= 8732
+ ok 4 - is like
+ not ok 5 - foo is greater than ten
+ # Failed test 'foo is greater than ten'
+ # at synopsis.c line 12.
+ # 3
+ # >=
+ # 10
+ # Looks like you failed 2 tests of 5 run.
+
+DESCRIPTION
+===========
+
+tap is an easy to read and easy to write way of creating tests for your
+software. This library creates functions that can be used to generate it for
+your C programs. It is mostly based on the Test::More Perl module.
+
+FUNCTIONS
+=========
+
+- plan(tests)
+- plan(NO_PLAN)
+
+ Use this to start a series of tests. When you know how many tests there
+ will be, you can put a number as a number of tests you expect to run. If
+ you do not know how many tests there will be, you can use plan(NO_PLAN)
+ or not call this function. When you pass it a number of tests to run, a
+ message similar to the following will appear in the output:
+
+ 1..5
+
+- ok(test)
+- ok(test, fmt, ...)
+
+ Specify a test. the test can be any statement returning a true or false
+ value. You may optionally pass a format string describing the test.
+
+ ok(r = reader_new("Of Mice and Men"), "create a new reader");
+ ok(reader_go_to_page(r, 55), "can turn the page");
+ ok(r->page == 55, "page turned to the right one");
+
+ Should print out:
+
+ ok 1 - create a new reader
+ ok 2 - can turn the page
+ ok 3 - page turned to the right one
+
+ On failure, a diagnostic message will be printed out.
+
+ not ok 3 - page turned to the right one
+ # Failed test 'page turned to the right one'
+ # at reader.c line 13.
+
+- is(got, expected)
+- is(got, expected, fmt, ...)
+- isnt(got, expected)
+- isnt(got, expected, fmt, ...)
+
+ Tests that the string you got is what you expected. with isnt, it is the
+ reverse.
+
+ is("this", "that", "this is that");
+
+ prints:
+
+ not ok 1 - this is that
+ # Failed test 'this is that'
+ # at is.c line 6.
+ # got: 'this'
+ # expected: 'that'
+
+- cmp_ok(a, op, b)
+- cmp_ok(a, op, b, fmt, ...)
+
+ Compares two ints with any binary operator that doesn't require an lvalue.
+ This is nice to use since it provides a better error message than an
+ equivalent ok.
+
+ cmp_ok(420, ">", 666);
+
+ prints:
+
+ not ok 1
+ # Failed test at cmpok.c line 5.
+ # 420
+ # >
+ # 666
+
+- like(got, expected)
+- like(got, expected, fmt, ...)
+- unlike(got, expected)
+- unlike(got, expected, fmt, ...)
+
+ Tests that the string you got matches the expected extended POSIX regex.
+ unlike is the reverse. These macros are the equivalent of a skip on
+ Windows.
+
+ like("stranger", "^s.(r).*\\1$", "matches the regex");
+
+ prints:
+
+ ok 1 - matches the regex
+
+- pass()
+- pass(fmt, ...)
+- fail()
+- fail(fmt, ...)
+
+ Speciy that a test succeeded or failed. Use these when the statement is
+ longer than you can fit into the argument given to an ok() test.
+
+- dies_ok(code)
+- dies_ok(code, fmt, ...)
+- lives_ok(code)
+- lives_ok(code, fmt, ...)
+
+ Tests whether the given code causes your program to exit. The code gets
+ passed to a macro that will test it in a forked process. If the code
+ succeeds it will be executed in the parent process. You can test things
+ like passing a function a null pointer and make sure it doesnt
+ dereference it and crash.
+
+ dies_ok({abort();}, "abort does close your program");
+ dies_ok({int x = 0/0;}, "divide by zero crash");
+ lives ok({pow(3.0, 5.0)}, "nothing wrong with taking 3**5");
+
+ On Windows, these macros are the equivalent of a skip.
+
+- exit_status()
+
+ Summarizes the tests that occurred. If there was no plan, it will print
+ out the number of tests as.
+
+ 1..5
+
+ It will also print a diagnostic message about how many
+ failures there were.
+
+ # Looks like you failed 2 tests of 3 run.
+
+ If all planned tests were successful, it will return 0. If any test fails,
+ it will return the number of failed tests (including ones that were
+ missing). If they all passed, but there were missing tests, it will return
+ 255.
+
+- note(fmt, ...)
+- diag(fmt, ...)
+
+ print out a message to the tap output. note prints to stdout and diag
+ prints to stderr. Each line is preceeded by a "# " so that you know its a
+ diagnostic message.
+
+ note("This is\na note\nto describe\nsomething.");
+
+ prints:
+
+ # This is
+ # a note
+ # to describe
+ # something
+
+ ok() and these functions return ints so you can use them like:
+
+ ok(1) && note("yo!");
+ ok(0) || diag("I have no idea what just happened");
+
+- skip(test, n)
+- skip(test, n, fmt, ...)
+- endskip
+
+ Skip a series of n tests if test is true. You may give a reason why you are
+ skipping them or not. The (possibly) skipped tests must occur between the
+ skip and endskip macros.
+
+ skip(TRUE, 2);
+ ok(1);
+ ok(0);
+ endskip;
+
+ prints:
+
+ ok 1 # skip
+ ok 2 # skip
+
+- todo()
+- todo(fmt, ...)
+- endtodo
+
+ Specifies a series of tests that you expect to fail because they are not
+ yet implemented.
+
+ todo()
+ ok(0);
+ endtodo;
+
+ prints:
+
+ not ok 1 # TODO
+ # Failed (TODO) test at todo.c line 7
+
diff --git a/src/common/libtap/tap.c b/src/common/libtap/tap.c
new file mode 100644
index 0000000..61e0528
--- /dev/null
+++ b/src/common/libtap/tap.c
@@ -0,0 +1,313 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+//#include "common.h"
+#include "tap.h"
+
+static int expected_tests = NO_PLAN;
+static int failed_tests;
+static int current_test;
+static char *todo_mesg;
+
+void
+plan (int tests) {
+ expected_tests = tests;
+ if (tests != NO_PLAN)
+ printf("1..%d\n", tests);
+}
+
+static char *
+vstrdupf (const char *fmt, va_list args) {
+ char *str;
+ int size;
+ va_list args2;
+ va_copy(args2, args);
+ if (!fmt)
+ fmt = "";
+ size = vsnprintf(NULL, 0, fmt, args2) + 2;
+ str = malloc(size);
+ vsprintf(str, fmt, args);
+ va_end(args2);
+ return str;
+}
+
+int
+vok_at_loc (const char *file, int line, int test, const char *fmt,
+ va_list args)
+{
+ char *name = vstrdupf(fmt, args);
+ printf("%sok %d", test ? "" : "not ", ++current_test);
+ if (*name)
+ printf(" - %s", name);
+ if (todo_mesg) {
+ printf(" # TODO");
+ if (*todo_mesg)
+ printf(" %s", todo_mesg);
+ }
+ printf("\n");
+ if (!test) {
+ if (*name)
+ diag(" Failed%s test '%s'\n at %s line %d.",
+ todo_mesg ? " (TODO)" : "", name, file, line);
+ else
+ diag(" Failed%s test at %s line %d.",
+ todo_mesg ? " (TODO)" : "", file, line);
+ if (!todo_mesg)
+ failed_tests++;
+ }
+ free(name);
+ return test;
+}
+
+int
+ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ return test;
+}
+
+static int
+mystrcmp (const char *a, const char *b) {
+ return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
+}
+
+#define eq(a, b) (!mystrcmp(a, b))
+#define ne(a, b) (mystrcmp(a, b))
+
+int
+is_at_loc (const char *file, int line, const char *got, const char *expected,
+ const char *fmt, ...)
+{
+ int test = eq(got, expected);
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ if (!test) {
+ diag(" got: '%s'", got);
+ diag(" expected: '%s'", expected);
+ }
+ return test;
+}
+
+int
+isnt_at_loc (const char *file, int line, const char *got, const char *expected,
+ const char *fmt, ...)
+{
+ int test = ne(got, expected);
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ if (!test) {
+ diag(" got: '%s'", got);
+ diag(" expected: anything else");
+ }
+ return test;
+}
+
+int
+cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
+ const char *fmt, ...)
+{
+ int test = eq(op, "||") ? a || b
+ : eq(op, "&&") ? a && b
+ : eq(op, "|") ? a | b
+ : eq(op, "^") ? a ^ b
+ : eq(op, "&") ? a & b
+ : eq(op, "==") ? a == b
+ : eq(op, "!=") ? a != b
+ : eq(op, "<") ? a < b
+ : eq(op, ">") ? a > b
+ : eq(op, "<=") ? a <= b
+ : eq(op, ">=") ? a >= b
+ : eq(op, "<<") ? a << b
+ : eq(op, ">>") ? a >> b
+ : eq(op, "+") ? a + b
+ : eq(op, "-") ? a - b
+ : eq(op, "*") ? a * b
+ : eq(op, "/") ? a / b
+ : eq(op, "%") ? a % b
+ : diag("unrecognized operator '%s'", op);
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ if (!test) {
+ diag(" %d", a);
+ diag(" %s", op);
+ diag(" %d", b);
+ }
+ return test;
+}
+
+static void
+vdiag_to_fh (FILE *fh, const char *fmt, va_list args) {
+ char *mesg, *line;
+ int i;
+ if (!fmt)
+ return;
+ mesg = vstrdupf(fmt, args);
+ line = mesg;
+ for (i = 0; *line; i++) {
+ char c = mesg[i];
+ if (!c || c == '\n') {
+ mesg[i] = '\0';
+ fprintf(fh, "# %s\n", line);
+ if (!c) break;
+ mesg[i] = c;
+ line = &mesg[i+1];
+ }
+ }
+ free(mesg);
+ return;
+}
+
+int
+diag (const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vdiag_to_fh(stderr, fmt, args);
+ va_end(args);
+ return 0;
+}
+
+int
+note (const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vdiag_to_fh(stdout, fmt, args);
+ va_end(args);
+ return 0;
+}
+
+int
+exit_status () {
+ int retval = 0;
+ if (expected_tests == NO_PLAN) {
+ printf("1..%d\n", current_test);
+ }
+ else if (current_test != expected_tests) {
+ diag("Looks like you planned %d test%s but ran %d.",
+ expected_tests, expected_tests > 1 ? "s" : "", current_test);
+ retval = 255;
+ }
+ if (failed_tests) {
+ diag("Looks like you failed %d test%s of %d run.",
+ failed_tests, failed_tests > 1 ? "s" : "", current_test);
+ if (expected_tests == NO_PLAN)
+ retval = failed_tests;
+ else
+ retval = expected_tests - current_test + failed_tests;
+ }
+ return retval;
+}
+
+void
+skippy (int n, const char *fmt, ...) {
+ char *why;
+ va_list args;
+ va_start(args, fmt);
+ why = vstrdupf(fmt, args);
+ va_end(args);
+ while (n --> 0) {
+ printf("ok %d ", ++current_test);
+ note("skip %s\n", why);
+ }
+ free(why);
+}
+
+void
+ctodo (int ignore, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ todo_mesg = vstrdupf(fmt, args);
+ va_end(args);
+}
+
+void
+cendtodo () {
+ free(todo_mesg);
+ todo_mesg = NULL;
+}
+
+#ifndef _WIN32
+#include <sys/mman.h>
+#include <regex.h>
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/* Create a shared memory int to keep track of whether a piece of code executed
+dies. to be used in the dies_ok and lives_ok macros */
+int
+tap_test_died (int status) {
+ static int *test_died = NULL;
+ int prev;
+ if (!test_died) {
+ test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ *test_died = 0;
+ }
+ prev = *test_died;
+ *test_died = status;
+ return prev;
+}
+
+int
+like_at_loc (int for_match, const char *file, int line, const char *got,
+ const char *expected, const char *fmt, ...)
+{
+ int test;
+ regex_t re;
+ int err = regcomp(&re, expected, REG_EXTENDED);
+ if (err) {
+ char errbuf[256];
+ regerror(err, &re, errbuf, sizeof errbuf);
+ fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
+ expected, errbuf, file, line);
+ exit(255);
+ }
+ err = regexec(&re, got, 0, NULL, 0);
+ regfree(&re);
+ test = for_match ? !err : err;
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ if (!test) {
+ if (for_match) {
+ diag(" '%s'", got);
+ diag(" doesn't match: '%s'", expected);
+ }
+ else {
+ diag(" '%s'", got);
+ diag(" matches: '%s'", expected);
+ }
+ }
+ return test;
+}
+#endif
+
diff --git a/src/common/libtap/tap.h b/src/common/libtap/tap.h
new file mode 100644
index 0000000..2e89b90
--- /dev/null
+++ b/src/common/libtap/tap.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TAP_H__
+#define __TAP_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define NO_PLAN -1
+#define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define pass(...) ok(1, ## __VA_ARGS__)
+#define fail(...) ok(0, ## __VA_ARGS__)
+#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+
+int vok_at_loc (const char *file, int line, int test, const char *fmt,
+ va_list args);
+void plan (int tests);
+int ok_at_loc (const char *file, int line, int test, const char *fmt,
+ ...);
+int diag (const char *fmt, ...);
+int note (const char *fmt, ...);
+int exit_status (void);
+void skippy (int n, const char *fmt, ...);
+void ctodo (int ignore, const char *fmt, ...);
+void cendtodo (void);
+int is_at_loc (const char *file, int line, const char *got,
+ const char *expected, const char *fmt, ...);
+int isnt_at_loc (const char *file, int line, const char *got,
+ const char *expected, const char *fmt, ...);
+int cmp_ok_at_loc (const char *file, int line, int a, const char *op,
+ int b, const char *fmt, ...);
+
+#ifdef _WIN32
+#define like(...) skippy(1, "like is not implemented on MSWin32")
+#define unlike(...) like()
+#else
+#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL)
+#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL)
+int like_at_loc (int for_match, const char *file, int line,
+ const char *got, const char *expected,
+ const char *fmt, ...);
+#endif
+
+#define skip(test, ...) do {if (test) {skippy(__VA_ARGS__, NULL); break;}
+#define endskip } while (0)
+
+#define todo(...) ctodo(0, ## __VA_ARGS__, NULL)
+#define endtodo cendtodo()
+
+#define dies_ok(code, ...) dies_ok_common(code, 1, ## __VA_ARGS__)
+#define lives_ok(code, ...) dies_ok_common(code, 0, ## __VA_ARGS__)
+
+#ifdef _WIN32
+#define dies_ok_common(...) \
+ skippy(1, "Death detection is not supported on MSWin32")
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+int tap_test_died (int status);
+#define dies_ok_common(code, for_death, ...) \
+ do { \
+ tap_test_died(1); \
+ int cpid = fork(); \
+ switch (cpid) { \
+ case -1: \
+ perror("fork error"); \
+ exit(EXIT_FAILURE); \
+ case 0: /* child */ \
+ close(1); close(2); \
+ code \
+ tap_test_died(0); \
+ exit(EXIT_SUCCESS); \
+ } \
+ if (waitpid(cpid, NULL, 0) < 0) { \
+ perror("waitpid error"); \
+ exit(EXIT_FAILURE); \
+ } \
+ int it_died = tap_test_died(0); \
+ if (!it_died) {code} \
+ ok(for_death ? it_died : !it_died, ## __VA_ARGS__); \
+ } while (0)
+#endif
+#endif
diff --git a/src/common/libtap/tap_unit.h b/src/common/libtap/tap_unit.h
new file mode 100644
index 0000000..c248fde
--- /dev/null
+++ b/src/common/libtap/tap_unit.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file tap_unit.h
+ * \author Marek Vavrusa <marek.vavusa@nic.cz>
+ *
+ * \brief libtap test unit.
+ *
+ * Contains description of a single test unit API.
+ *
+ * Export unit_api in each module header file,
+ * and set function pointer to according test routines.
+ *
+ * <b>Example code for myunit.h</b>
+ * \code
+ * #ifndef MYUNIT_TEST_H
+ * #define MYUNIT_TEST_H
+ *
+ * // Export unittest symbol
+ * unit_api mymodule;
+ *
+ * #endif // MYUNIT_TEST_H
+ * \endcode
+ *
+ * <b>Example code for myunit.c</b>
+ * \code
+ * #include "myunit.h"
+ *
+ * // Function to return unit test count
+ * int myunit_count(int argc, char *argv[]) {
+ * return 1; // Number of tests in this unit
+ * }
+ *
+ * // Function to perform tests
+ * int myunit_run(int argc, char *argv[]) {
+ * // 1. test
+ * ok(1 == 1, "test OK");
+ * return 0;
+ * }
+ *
+ * // Declare module API
+ * unit_api mymodule = {
+ * "My module",
+ * &myunit_count,
+ * &myunit_run
+ * };
+ * \endcode
+ *
+ * To incorporate test, add it to unit tests main().
+ *
+ * See https://github.com/zorgnax/libtap for libtap API reference.
+ *
+ * \addtogroup tests
+ * @{
+ */
+
+#ifndef _TAP_UNIT_H_
+#define _TAP_UNIT_H_
+
+#include "common/libtap/tap.h"
+
+/*! \brief Pointer to function for unit_api. */
+typedef int(unitapi_f)(int, char*[]);
+
+
+/*!
+ * \brief Basic Unit APIs.
+ *
+ * Each unit should have one global variable with
+ * an initialized instance of unit_api.
+ */
+typedef struct {
+ const char *name; /*!< Test unit name. */
+ unitapi_f *count; /*!< Function to calculate number of tests. */
+ unitapi_f *run; /*!< Function to run unit tests. */
+} unit_api;
+
+#endif // _TAP_UNIT_H_
+
+/*! @} */
+
diff --git a/src/common/lists.c b/src/common/lists.c
new file mode 100644
index 0000000..9a93733
--- /dev/null
+++ b/src/common/lists.c
@@ -0,0 +1,160 @@
+/*
+ * BIRD Library -- Linked Lists
+ *
+ * (c) 1998 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/**
+ * DOC: Linked lists
+ *
+ * The BIRD library provides a set of functions for operating on linked
+ * lists. The lists are internally represented as standard doubly linked
+ * lists with synthetic head and tail which makes all the basic operations
+ * run in constant time and contain no extra end-of-list checks. Each list
+ * is described by a &list structure, nodes can have any format as long
+ * as they start with a &node structure. If you want your nodes to belong
+ * to multiple lists at once, you can embed multiple &node structures in them
+ * and use the SKIP_BACK() macro to calculate a pointer to the start of the
+ * structure from a &node pointer, but beware of obscurity.
+ *
+ * There also exist safe linked lists (&slist, &snode and all functions
+ * being prefixed with |s_|) which support asynchronous walking very
+ * similar to that used in the &fib structure.
+ */
+
+#define _BIRD_LISTS_C_
+
+#include <stdlib.h>
+#include <string.h>
+#include "common/lists.h"
+
+/**
+ * add_tail - append a node to a list
+ * @l: linked list
+ * @n: list node
+ *
+ * add_tail() takes a node @n and appends it at the end of the list @l.
+ */
+LIST_INLINE void
+add_tail(list *l, node *n)
+{
+ node *z = l->tail;
+
+ n->next = (node *) &l->null;
+ n->prev = z;
+ z->next = n;
+ l->tail = n;
+}
+
+/**
+ * add_head - prepend a node to a list
+ * @l: linked list
+ * @n: list node
+ *
+ * add_head() takes a node @n and prepends it at the start of the list @l.
+ */
+LIST_INLINE void
+add_head(list *l, node *n)
+{
+ node *z = l->head;
+
+ n->next = z;
+ n->prev = (node *) &l->head;
+ z->prev = n;
+ l->head = n;
+}
+
+/**
+ * insert_node - insert a node to a list
+ * @n: a new list node
+ * @after: a node of a list
+ *
+ * Inserts a node @n to a linked list after an already inserted
+ * node @after.
+ */
+LIST_INLINE void
+insert_node(node *n, node *after)
+{
+ node *z = after->next;
+
+ n->next = z;
+ n->prev = after;
+ after->next = n;
+ z->prev = n;
+}
+
+/**
+ * rem_node - remove a node from a list
+ * @n: node to be removed
+ *
+ * Removes a node @n from the list it's linked in.
+ */
+LIST_INLINE void
+rem_node(node *n)
+{
+ node *z = n->prev;
+ node *x = n->next;
+
+ z->next = x;
+ x->prev = z;
+ n->prev = 0;
+ n->next = 0;
+}
+
+/**
+ * init_list - create an empty list
+ * @l: list
+ *
+ * init_list() takes a &list structure and initializes its
+ * fields, so that it represents an empty list.
+ */
+LIST_INLINE void
+init_list(list *l)
+{
+ l->head = (node *) &l->null;
+ l->null = NULL;
+ l->tail = (node *) &l->head;
+}
+
+/**
+ * add_tail_list - concatenate two lists
+ * @to: destination list
+ * @l: source list
+ *
+ * This function appends all elements of the list @l to
+ * the list @to in constant time.
+ */
+LIST_INLINE void
+add_tail_list(list *to, list *l)
+{
+ node *p = to->tail;
+ node *q = l->head;
+
+ p->next = q;
+ q->prev = p;
+ q = l->tail;
+ q->next = (node *) &to->null;
+ to->tail = q;
+}
+
+/**
+ * list_dup - duplicate list
+ * @to: destination list
+ * @l: source list
+ *
+ * This function duplicates all elements of the list @l to
+ * the list @to in linear time.
+ *
+ * This function only works with a homogenous item size.
+ */
+void list_dup(list *dst, list *src, size_t itemsz)
+{
+ node *n = 0;
+ WALK_LIST(n, *src) {
+ node *i = malloc(itemsz);
+ memcpy(i, n, itemsz);
+ add_tail(dst, i);
+ }
+}
diff --git a/src/common/lists.h b/src/common/lists.h
new file mode 100644
index 0000000..972ea49
--- /dev/null
+++ b/src/common/lists.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * BIRD Library -- Linked Lists
+ *
+ * (c) 1998 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_LISTS_H_
+#define _BIRD_LISTS_H_
+
+/*
+ * I admit the list structure is very tricky and also somewhat awkward,
+ * but it's both efficient and easy to manipulate once one understands the
+ * basic trick: The list head always contains two synthetic nodes which are
+ * always present in the list: the head and the tail. But as the `next'
+ * entry of the tail and the `prev' entry of the head are both NULL, the
+ * nodes can overlap each other:
+ *
+ * head head_node.next
+ * null head_node.prev tail_node.next
+ * tail tail_node.prev
+ */
+
+#include <string.h> // size_t
+
+typedef struct node {
+ struct node *next, *prev;
+} node;
+
+typedef struct list { /* In fact two overlayed nodes */
+ struct node *head, *null, *tail;
+} list;
+
+#define NODE (node *)
+#define HEAD(list) ((void *)((list).head))
+#define TAIL(list) ((void *)((list).tail))
+#define WALK_LIST(n,list) for(n=HEAD(list);(NODE (n))->next; \
+ n=(void *)((NODE (n))->next))
+#define WALK_LIST_DELSAFE(n,nxt,list) \
+ for(n=HEAD(list); (nxt=(void *)((NODE (n))->next)); n=(void *) nxt)
+/* WALK_LIST_FIRST supposes that called code removes each processed node */
+#define WALK_LIST_FIRST(n,list) \
+ while(n=HEAD(list), (NODE (n))->next)
+#define WALK_LIST_BACKWARDS(n,list) for(n=TAIL(list);(NODE (n))->prev; \
+ n=(void *)((NODE (n))->prev))
+#define WALK_LIST_BACKWARDS_DELSAFE(n,prv,list) \
+ for(n=TAIL(list); prv=(void *)((NODE (n))->prev); n=(void *) prv)
+
+#define EMPTY_LIST(list) (!(list).head->next)
+
+/*! \brief Free every node in the list. */
+#define WALK_LIST_FREE(list) \
+ do { \
+ node *n=0,*nxt=0; \
+ WALK_LIST_DELSAFE(n,nxt,list) { \
+ free(n); \
+ } \
+ } while(0)
+
+void add_tail(list *, node *);
+void add_head(list *, node *);
+void rem_node(node *);
+void add_tail_list(list *, list *);
+void init_list(list *);
+void insert_node(node *, node *);
+void list_dup(list *dst, list *src, size_t itemsz);
+
+/*!
+ * \brief List item for string lists.
+ */
+typedef struct strnode_t {
+ node n;
+ char *str;
+} strnode_t;
+
+/*! \todo This is broken atm.
+#ifndef _BIRD_LISTS_C_
+#define LIST_INLINE extern inline
+#include "knot/lib/lists.c"
+#undef LIST_INLINE
+#else
+#define LIST_INLINE
+#endif
+*/
+#define LIST_INLINE
+
+#endif
diff --git a/src/common/modified_tree.h b/src/common/modified_tree.h
new file mode 100644
index 0000000..4c3e325
--- /dev/null
+++ b/src/common/modified_tree.h
@@ -0,0 +1,292 @@
+/* tree.h -- AVL trees (in the spirit of BSD's 'queue.h') -*- C -*- */
+
+/* Copyright (c) 2005 Ian Piumarta
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the 'Software'), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * provided that the above copyright notice(s) and this permission notice appear
+ * in all copies of the Software and that both the above copyright notice(s) and
+ * this permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
+ */
+
+/* This file defines an AVL balanced binary tree [Georgii M. Adelson-Velskii and
+ * Evgenii M. Landis, 'An algorithm for the organization of information',
+ * Doklady Akademii Nauk SSSR, 146:263-266, 1962 (Russian). Also in Myron
+ * J. Ricci (trans.), Soviet Math, 3:1259-1263, 1962 (English)].
+ *
+ * An AVL tree is headed by pointers to the root node and to a function defining
+ * the ordering relation between nodes. Each node contains an arbitrary payload
+ * plus three fields per tree entry: the depth of the subtree for which it forms
+ * the root and two pointers to child nodes (singly-linked for minimum space, at
+ * the expense of direct access to the parent node given a pointer to one of the
+ * children). The tree is rebalanced after every insertion or removal. The
+ * tree may be traversed in two directions: forward (in-order left-to-right) and
+ * reverse (in-order, right-to-left).
+ *
+ * Because of the recursive nature of many of the operations on trees it is
+ * necessary to define a number of helper functions for each type of tree node.
+ * The macro TREE_DEFINE(node_tag, entry_name) defines these functions with
+ * unique names according to the node_tag. This macro should be invoked,
+ * thereby defining the necessary functions, once per node tag in the program.
+ *
+ * For details on the use of these macros, see the tree(3) manual page.
+ */
+
+#ifndef _modified_tree_h
+#define _modified_tree_h
+
+
+#define MOD_TREE_DELTA_MAX 1
+
+#define MOD_TREE_ENTRY(type) \
+ struct { \
+ struct type *avl_left; \
+ struct type *avl_right; \
+ int avl_height; \
+ }
+
+#define MOD_TREE_HEAD(name, type) \
+ struct name { \
+ struct type *th_root; \
+ int (*th_cmp)(void *lhs, void *rhs); \
+ }
+
+#define MOD_TREE_INITIALIZER(cmp) { 0, cmp}
+
+#define MOD_TREE_DELTA(self, field) \
+ (( (((self)->field.avl_left) ? (self)->field.avl_left->field.avl_height : 0)) \
+ - (((self)->field.avl_right) ? (self)->field.avl_right->field.avl_height : 0))
+
+/* Recursion prevents the following from being defined as macros. */
+
+#define MOD_TREE_DEFINE(node, field) \
+ \
+ struct node *MOD_TREE_BALANCE_##node##_##field(struct node *); \
+ \
+ struct node *MOD_TREE_ROTL_##node##_##field(struct node *self) \
+ { \
+ struct node *r= self->field.avl_right; \
+ self->field.avl_right= r->field.avl_left; \
+ r->field.avl_left= MOD_TREE_BALANCE_##node##_##field(self); \
+ return MOD_TREE_BALANCE_##node##_##field(r); \
+ } \
+ \
+ struct node *MOD_TREE_ROTR_##node##_##field(struct node *self) \
+ { \
+ struct node *l= self->field.avl_left; \
+ self->field.avl_left= l->field.avl_right; \
+ l->field.avl_right= MOD_TREE_BALANCE_##node##_##field(self); \
+ return MOD_TREE_BALANCE_##node##_##field(l); \
+ } \
+ \
+ struct node *MOD_TREE_BALANCE_##node##_##field(struct node *self) \
+ { \
+ int delta= MOD_TREE_DELTA(self, field); \
+ \
+ if (delta < -MOD_TREE_DELTA_MAX) \
+ { \
+ if (MOD_TREE_DELTA(self->field.avl_right, field) > 0) \
+ self->field.avl_right= MOD_TREE_ROTR_##node##_##field(self->field.avl_right); \
+ return MOD_TREE_ROTL_##node##_##field(self); \
+ } \
+ else if (delta > MOD_TREE_DELTA_MAX) \
+ { \
+ if (MOD_TREE_DELTA(self->field.avl_left, field) < 0) \
+ self->field.avl_left= MOD_TREE_ROTL_##node##_##field(self->field.avl_left); \
+ return MOD_TREE_ROTR_##node##_##field(self); \
+ } \
+ self->field.avl_height= 0; \
+ if (self->field.avl_left && (self->field.avl_left->field.avl_height > self->field.avl_height)) \
+ self->field.avl_height= self->field.avl_left->field.avl_height; \
+ if (self->field.avl_right && (self->field.avl_right->field.avl_height > self->field.avl_height)) \
+ self->field.avl_height= self->field.avl_right->field.avl_height; \
+ self->field.avl_height += 1; \
+ return self; \
+ } \
+ \
+ struct node *MOD_TREE_INSERT_##node##_##field \
+ (struct node *self, struct node *elm, int (*compare)(void *lhs, void *rhs), int (*merge)(void **lhs, void **rhs), int *merged)\
+ { \
+ if (!self) { \
+ *merged = 0; \
+ return elm; } \
+ int cmp = compare(elm->data, self->data); \
+ if (cmp < 0) \
+ self->field.avl_left= MOD_TREE_INSERT_##node##_##field(self->field.avl_left, elm, compare, merge, merged); \
+ else if (cmp > 0) \
+ self->field.avl_right= MOD_TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare, merge, merged); \
+ else if (merge) { \
+ merge(&(elm->data), &(self->data)); \
+ *merged = 1; } \
+ else \
+ self->field.avl_right= MOD_TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare, merge, merged); \
+ return MOD_TREE_BALANCE_##node##_##field(self); \
+ } \
+ \
+ struct node *MOD_TREE_FIND_##node##_##field \
+ (struct node *self, struct node *elm, int (*compare)(void *lhs, void *rhs)) \
+ { \
+ if (!compare) \
+ return 0; \
+ if (!self) \
+ return 0; \
+ if (compare(elm->data, self->data) == 0) \
+ return self; \
+ if (compare(elm->data, self->data) < 0) \
+ return MOD_TREE_FIND_##node##_##field(self->field.avl_left, elm, compare); \
+ else \
+ return MOD_TREE_FIND_##node##_##field(self->field.avl_right, elm, compare); \
+ } \
+ \
+ int MOD_TREE_FIND_LESS_EQUAL_##node##_##field \
+ (struct node *self, struct node *elm, int (*compare)(void *lhs, void *rhs), struct node **found, struct node **prev) \
+ { \
+ if (!self) \
+ return 0; \
+ if (compare(elm->data, self->data) == 0) { \
+ *found = self; \
+ return 1; \
+ } \
+ if (compare(elm->data, self->data) < 0) { \
+ int ret = MOD_TREE_FIND_LESS_EQUAL_##node##_##field(self->field.avl_left, elm, compare, found, prev); \
+ if (ret == 0 && *prev == NULL) { \
+ *prev = self; \
+ ret = -1; \
+ } \
+ return ret; \
+ } else { \
+ *found = self; \
+ *prev = self; \
+ return MOD_TREE_FIND_LESS_EQUAL_##node##_##field(self->field.avl_right, elm, compare, found, prev); \
+ } \
+ } \
+ \
+ struct node *MOD_TREE_MOVE_RIGHT_##node##_##field(struct node *self, struct node *rhs) \
+ { \
+ if (!self) \
+ return rhs; \
+ self->field.avl_right= MOD_TREE_MOVE_RIGHT_##node##_##field(self->field.avl_right, rhs); \
+ return MOD_TREE_BALANCE_##node##_##field(self); \
+ } \
+ \
+ struct node *MOD_TREE_REMOVE_##node##_##field \
+ (struct node *self, struct node *elm, int (*compare)(void *lhs, void *rhs), void (*del)(struct node *lhs)) \
+ { \
+ if (!self) return 0; \
+ \
+ if (compare(elm->data, self->data) == 0) \
+ { \
+ struct node *tmp= MOD_TREE_MOVE_RIGHT_##node##_##field(self->field.avl_left, self->field.avl_right); \
+ self->field.avl_left= 0; \
+ self->field.avl_right= 0; \
+ del(self); \
+ return tmp; \
+ } \
+ if (compare(elm->data, self->data) < 0) \
+ self->field.avl_left= MOD_TREE_REMOVE_##node##_##field(self->field.avl_left, elm, compare, del); \
+ else \
+ self->field.avl_right= MOD_TREE_REMOVE_##node##_##field(self->field.avl_right, elm, compare, del); \
+ return MOD_TREE_BALANCE_##node##_##field(self); \
+ } \
+ \
+ void MOD_TREE_FORWARD_APPLY_ALL_##node##_##field \
+ (struct node *self, void (*function)(void *node, void *data), void *data) \
+ { \
+ if (self) \
+ { \
+ MOD_TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
+ function(self->data, data); \
+ MOD_TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
+ } \
+ } \
+ \
+ void MOD_TREE_REVERSE_APPLY_ALL_##node##_##field \
+ (struct node *self, void (*function)(struct node *node, void *data), void *data) \
+ { \
+ if (self) \
+ { \
+ MOD_TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
+ function(self, data); \
+ MOD_TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
+ } \
+ } \
+ \
+ void MOD_TREE_POST_ORDER_APPLY_ALL_##node##_##field \
+ (struct node *self, void (*function)(struct node *node, void *data), void *data) \
+ { \
+ if (self) \
+ { \
+ MOD_TREE_POST_ORDER_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
+ MOD_TREE_POST_ORDER_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
+ function(self, data); \
+ } \
+ } \
+ \
+void MOD_TREE_DESTROY_ALL_##node##_##field \
+ (struct node *self, void (*function)(void *node, void *data), void(*dest)(struct node *node), void *data) \
+{ \
+ if (self) \
+ { \
+ MOD_TREE_DESTROY_ALL_##node##_##field(self->field.avl_left, function, dest, data); \
+ MOD_TREE_DESTROY_ALL_##node##_##field(self->field.avl_right, function, dest, data); \
+ if (function != NULL) \
+ function(self->data, data); \
+ dest(self); \
+ } \
+} \
+ \
+ void MOD_TREE_REVERSE_APPLY_POST_ALL_##node##_##field \
+ (struct node *self, void (*function)(struct node *node, void *data), void *data) \
+ { \
+ if (self) \
+ { \
+ MOD_TREE_REVERSE_APPLY_POST_ALL_##node##_##field(self->field.avl_right, function, data); \
+ MOD_TREE_REVERSE_APPLY_POST_ALL_##node##_##field(self->field.avl_left, function, data); \
+ function(self, data); \
+ } \
+}
+
+#define MOD_TREE_INSERT(head, node, field, elm, merge, merged) \
+ ((head)->th_root= MOD_TREE_INSERT_##node##_##field((head)->th_root, (elm), (head)->th_cmp, merge, merged))
+
+#define MOD_TREE_FIND(head, node, field, elm) \
+ (MOD_TREE_FIND_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
+
+#define MOD_TREE_FIND_LESS_EQUAL(head, node, field, elm, found, prev) \
+ (MOD_TREE_FIND_LESS_EQUAL_##node##_##field((head)->th_root, (elm), (head)->th_cmp, found, prev))
+
+#define MOD_TREE_REMOVE(head, node, field, elm, rem) \
+ ((head)->th_root= MOD_TREE_REMOVE_##node##_##field((head)->th_root, (elm), (head)->th_cmp, (rem)))
+
+#define MOD_TREE_DEPTH(head, field) \
+ ((head)->th_root->field.avl_height)
+
+#define MOD_TREE_FORWARD_APPLY(head, node, field, function, data) \
+ MOD_TREE_FORWARD_APPLY_ALL_##node##_##field((head)->th_root, function, data)
+
+#define MOD_TREE_REVERSE_APPLY(head, node, field, function, data) \
+ MOD_TREE_REVERSE_APPLY_ALL_##node##_##field((head)->th_root, function, data)
+
+#define MOD_TREE_POST_ORDER_APPLY(head, node, field, function, data) \
+ MOD_TREE_POST_ORDER_APPLY_ALL_##node##_##field((head)->th_root, function, data)
+
+#define MOD_TREE_DESTROY(head, node, field, function, dest, data) \
+ MOD_TREE_DESTROY_ALL_##node##_##field((head)->th_root, function, dest, data)
+
+#define MOD_TREE_REVERSE_APPLY_POST(head, node, field, function, data) \
+ MOD_TREE_REVERSE_APPLY_POST_ALL_##node##_##field((head)->th_root, function, data)
+
+#define MOD_TREE_INIT(head, cmp) do { \
+ (head)->th_root= 0; \
+ (head)->th_cmp= (cmp); \
+ } while (0)
+
+
+#endif /* __MOD_TREE_h */
diff --git a/src/common/print.c b/src/common/print.c
new file mode 100644
index 0000000..9764568
--- /dev/null
+++ b/src/common/print.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "print.h"
+
+void hex_printf(const char *data, int length, printf_t print_handler)
+{
+ int ptr = 0;
+ for (; ptr < length; ptr++) {
+ print_handler("0x%02x ", (unsigned char)*(data + ptr));
+ }
+ print_handler("\n");
+}
+
+void hex_print(const char *data, int length)
+{
+ hex_printf(data, length, &printf);
+}
+
+void bit_printf(const char *data, int length, printf_t print_handler)
+{
+ unsigned char mask = 0x01;
+ int ptr = 0;
+ int bit = 0;
+ for (; ptr < length; ptr++) {
+ for (bit = 7; bit >= 0; bit--) {
+ if ((mask << bit) & (unsigned char)*(data + ptr)) {
+ print_handler("1");
+ } else {
+ print_handler("0");
+ }
+ }
+ print_handler(" ");
+ }
+ print_handler("\n");
+}
+
+void bit_print(const char *data, int length)
+{
+ bit_printf(data, length, &printf);
+}
diff --git a/src/common/print.h b/src/common/print.h
new file mode 100644
index 0000000..482f55e
--- /dev/null
+++ b/src/common/print.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file print.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Custom printing functions.
+ *
+ * Downloaded hex_print, bit_print from http://www.digitalpeer.com/id/print
+ * Updated with generic printf handler.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_PRINT_H_
+#define _KNOTD_COMMON_PRINT_H_
+
+typedef int (*printf_t)(const char *fmt, ...);
+
+/*!
+ * \brief Prints the given data as hexadecimal characters.
+ *
+ * \param data Data to print.
+ * \param length Size of the \a data array.
+ */
+void hex_print(const char *data, int length);
+
+/*!
+ * \brief Prints the given data as hexadecimal characters using the given
+ * handler.
+ *
+ * \param data Data to print.
+ * \param length Size of the \a data array.
+ * \param print_handler Handler for printing.
+ */
+void hex_printf(const char *data, int length, printf_t print_handler);
+
+/*!
+ * \brief Prints the given data as a bitmap.
+ *
+ * \param data Data to print.
+ * \param length Size of the \a data array.
+ */
+void bit_print(const char *data, int length);
+
+/*!
+ * \brief Prints the given data as a bitmap using the given handler.
+ *
+ * \param data Data to print.
+ * \param length Size of the \a data array.
+ * \param print_handler Handler for printing.
+ */
+void bit_printf(const char *data, int length, printf_t print_handler);
+
+#endif /* _KNOTD_COMMON_PRINT_H_ */
+
+/*! @} */
diff --git a/src/common/ref.c b/src/common/ref.c
new file mode 100644
index 0000000..3b9c033
--- /dev/null
+++ b/src/common/ref.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include "ref.h"
+
+void ref_init(ref_t *p, ref_destructor_t dtor)
+{
+ if (p) {
+ p->count = 0;
+ p->dtor = dtor;
+ }
+}
+
+void ref_retain(ref_t *p)
+{
+ if (p) {
+ __sync_add_and_fetch(&p->count, 1);
+ }
+}
+
+void ref_release(ref_t *p)
+{
+ if (p) {
+ int rc = __sync_sub_and_fetch(&p->count, 1);
+ if (rc == 0 && p->dtor) {
+ p->dtor(p);
+ }
+ }
+}
diff --git a/src/common/ref.h b/src/common/ref.h
new file mode 100644
index 0000000..13a7037
--- /dev/null
+++ b/src/common/ref.h
@@ -0,0 +1,90 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file ref.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Atomic reference counting structures.
+ *
+ * Reference counting allows implicit sharing of objects
+ * between threads with custom destructor functions.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_REF_H_
+#define _KNOTD_REF_H_
+
+#include <stddef.h>
+
+struct ref_t;
+
+/*! \brief Prototype for object destructor callback. */
+typedef void (*ref_destructor_t)(struct ref_t * p);
+
+/*!
+ * \brief Structure for reference counting.
+ *
+ * Size equals to two sizes of pointer size.
+ * Structure may be embedded to the structures which
+ * we want to use for reference counting.
+ *
+ * \code
+ * struct mystruct {
+ * ref_t ref;
+ * int mydata;
+ * char *mystr;
+ * }
+ * \endcode
+ */
+typedef struct ref_t {
+ size_t count; /*! \brief Reference counter. */
+ ref_destructor_t dtor; /*! \brief Object destructor function. */
+} ref_t;
+
+/*!
+ * \brief Initialize reference counter.
+ *
+ * Set reference counter to 0 and initialize destructor callback.
+ *
+ * \param p Reference-counted object.
+ * \param dtor Destructor function.
+ */
+void ref_init(ref_t *p, ref_destructor_t dtor);
+
+/*!
+ * \brief Mark object as used by the caller.
+ *
+ * Reference counter will be incremented.
+ *
+ * \param p Reference-counted object.
+ */
+void ref_retain(ref_t *p);
+
+/*!
+ * \brief Marks object as unused by the caller.
+ *
+ * Reference counter will be decremented.
+ *
+ * \param p Reference-counted object.
+ */
+void ref_release(ref_t *p);
+
+#endif /* _KNOTD_REF_H_ */
+
+/*! @} */
diff --git a/src/common/skip-list.c b/src/common/skip-list.c
new file mode 100644
index 0000000..79e9429
--- /dev/null
+++ b/src/common/skip-list.c
@@ -0,0 +1,437 @@
+/* Copyright (c) 2010 the authors listed at the following URL, and/or
+the authors of referenced articles or incorporated external code:
+http://en.literateprograms.org/Skip_list_(C)?action=history&offset=20080313195128
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Retrieved from: http://en.literateprograms.org/Skip_list_(C)?oldid=12811
+*/
+
+/*
+ * Modifications by Lubos Slovak, 2010-2011
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <assert.h>
+
+//#include "common.h"
+#include "common/skip-list.h"
+
+#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d\n", \
+ __FILE__, __LINE__)
+
+/*----------------------------------------------------------------------------*/
+
+static const float P = 0.5;
+
+/*!
+ * \brief Maximum level of a node, i.e. maximum number of skip list levels.
+ */
+static const int MAX_LEVEL = 6;
+
+/*----------------------------------------------------------------------------*/
+/* Private functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Generates random real number between 0 and 1.
+ */
+static float frand()
+{
+ unsigned seed = (unsigned)time(0);
+ return (float) rand_r(&seed) / RAND_MAX;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Returns random level between 0 and MAX_LEVEL.
+ */
+static int skip_random_level()
+{
+ static int first = 1;
+ int lvl = 0;
+
+ if (first) {
+ first = 0;
+ }
+
+ while (frand() < P && lvl < MAX_LEVEL) {
+ lvl++;
+ }
+
+ return lvl;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates a new skip list node with the given key and value.
+ *
+ * \param level Level of the skip list node.
+ * \param key Key of the new node.
+ * \param value Value to be stored in the node.
+ *
+ * \return Pointer to the newly created node or NULL if not successful.
+ */
+static skip_node_t *skip_make_node(int level, void *key, void *value)
+{
+ skip_node_t *sn = (skip_node_t *)malloc(sizeof(skip_node_t));
+ if (sn == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ sn->forward = (skip_node_t **)calloc(level + 1, sizeof(skip_node_t *));
+ if (sn->forward == NULL) {
+ ERR_ALLOC_FAILED;
+ free(sn);
+ return NULL;
+ }
+ sn->key = key;
+ sn->value = value;
+ return sn;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Properly deallocates the given skip list node, and optionally destroys
+ * its key and value.
+ *
+ * \param node Skip list node to be deleted.
+ * \param destroy_key Function for properly destroying the key. If set tu NULL,
+ * the object at which the key points will not be destroyed.
+ * \param destroy_value Function for properly destroying the key. If set tu
+ * NULL, the object at which the value points will not be
+ * destroyed.
+ */
+static void skip_delete_node(skip_node_t **node, void (*destroy_key)(void *),
+ void (*destroy_value)(void *))
+{
+ if (destroy_key != NULL) {
+ destroy_key((*node)->key);
+ }
+ if (destroy_value != NULL) {
+ destroy_value((*node)->value);
+ }
+
+ free((*node)->forward);
+ free(*node);
+
+ node = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Public functions */
+/*----------------------------------------------------------------------------*/
+
+skip_list_t *skip_create_list(int (*compare_keys)(void *, void *))
+{
+ assert(compare_keys != NULL);
+
+ skip_list_t *ss = (skip_list_t *)malloc(sizeof(skip_list_t));
+ if (ss == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ ss->head = skip_make_node(MAX_LEVEL, NULL, NULL);
+ if (ss->head == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ss);
+ return NULL;
+ }
+
+ ss->level = 0;
+ ss->compare_keys = compare_keys;
+
+ return ss;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void skip_destroy_list(skip_list_t **list, void (*destroy_key)(void *),
+ void (*destroy_value)(void *))
+{
+ assert((*list) != NULL);
+ assert((*list)->head != NULL);
+
+ skip_node_t *x;
+
+ while ((*list)->head->forward[0] != NULL) {
+ x = (*list)->head->forward[0];
+ for (int i = 0; i <= (*list)->level; i++) {
+ if ((*list)->head->forward[i] != x) {
+ break;
+ }
+ (*list)->head->forward[i] = x->forward[i];
+ }
+
+ // delete the item
+ skip_delete_node(&x, destroy_key, destroy_value);
+
+ while ((*list)->level > 0
+ && (*list)->head->forward[(*list)->level] == NULL) {
+ (*list)->level--;
+ }
+ }
+
+ // free the head
+ skip_delete_node(&(*list)->head, NULL, NULL);
+
+ free(*list);
+ *list = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void *skip_find(const skip_list_t *list, void *key)
+{
+ assert(list != NULL);
+ assert(list->head != NULL);
+ assert(list->compare_keys != NULL);
+
+ int i;
+ skip_node_t *x = list->head;
+ for (i = list->level; i >= 0; i--) {
+ while (x->forward[i] != NULL
+ && list->compare_keys(x->forward[i]->key, key) == -1) {
+ x = x->forward[i];
+ }
+ }
+ x = x->forward[0];
+
+ if (x != NULL && list->compare_keys(x->key, key) == 0) {
+ return x->value;
+ }
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void *skip_find_less_or_equal(const skip_list_t *list, void *key)
+{
+ assert(list != NULL);
+ assert(list->head != NULL);
+ assert(list->compare_keys != NULL);
+
+ int i;
+ skip_node_t *x = list->head;
+ for (i = list->level; i >= 0; i--) {
+ while (x->forward[i] != NULL
+ && list->compare_keys(x->forward[i]->key, key) <= 0) {
+ x = x->forward[i];
+ }
+ }
+
+ return x->value;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int skip_insert(skip_list_t *list, void *key, void *value,
+ int (*merge_values)(void **, void **))
+{
+ assert(list != NULL);
+ assert(list->head != NULL);
+ assert(list->compare_keys != NULL);
+
+ int i;
+ skip_node_t *x = list->head;
+ skip_node_t *update[MAX_LEVEL + 1];
+ memset(update, 0, MAX_LEVEL + 1);
+
+ for (i = list->level; i >= 0; i--) {
+ while (x->forward[i] != NULL
+ && list->compare_keys(x->forward[i]->key, key) == -1) {
+ x = x->forward[i];
+ }
+ update[i] = x;
+ }
+ x = x->forward[0];
+
+ if (x == NULL || list->compare_keys(x->key, key) != 0) {
+ int lvl = skip_random_level();
+
+ if (lvl > list->level) {
+ for (i = list->level + 1; i <= lvl; i++) {
+ update[i] = list->head;
+ }
+ list->level = lvl;
+ }
+
+ x = skip_make_node(lvl, key, value);
+ if (x == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ for (i = 0; i <= lvl; i++) {
+ x->forward[i] = update[i]->forward[i];
+ update[i]->forward[i] = x;
+ }
+
+ return 0;
+ } else { // already in the list
+ if (merge_values != NULL) { // if merge function provided, merge
+ return (merge_values(&x->value, &value) == 0) ? 2 : -2;
+ } else {
+ return 1;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int skip_remove(skip_list_t *list, void *key, void (*destroy_key)(void *),
+ void (*destroy_value)(void *))
+{
+ assert(list != NULL);
+ assert(list->head != NULL);
+ assert(list->compare_keys != NULL);
+
+ int i;
+ skip_node_t *x = list->head;
+ skip_node_t *update[MAX_LEVEL + 1];
+ memset(update, 0, MAX_LEVEL + 1);
+
+ for (i = list->level; i >= 0; i--) {
+ while (x->forward[i] != NULL
+ && list->compare_keys(x->forward[i]->key, key) == -1) {
+ x = x->forward[i];
+ }
+ update[i] = x;
+ }
+ x = x->forward[0];
+
+ if (x != NULL && list->compare_keys(x->key, key) == 0) {
+ for (i = 0; i <= list->level; i++) {
+ if (update[i]->forward[i] != x) {
+ break;
+ }
+ update[i]->forward[i] = x->forward[i];
+ }
+
+ // delete the item
+ skip_delete_node(&x, destroy_key, destroy_value);
+
+ while (list->level > 0
+ && list->head->forward[list->level] == NULL) {
+ list->level--;
+ }
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int skip_is_empty(const skip_list_t *list)
+{
+ if (!list) {
+ return 1;
+ }
+
+ return (list->head->forward[0] == NULL);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const skip_node_t *skip_first(const skip_list_t *list)
+{
+ if (!list) {
+ return NULL;
+ }
+
+ return list->head->forward[0];
+}
+
+/*----------------------------------------------------------------------------*/
+
+const skip_node_t *skip_next(const skip_node_t *node)
+{
+ return node->forward[0];
+}
+
+/*----------------------------------------------------------------------------*/
+
+void skip_print_list(const skip_list_t *list,
+ void (*print_item)(void *, void *))
+{
+ assert(list != NULL);
+ assert(list->head != NULL);
+ assert(list->compare_keys != NULL);
+ assert(print_item != NULL);
+
+ skip_node_t *x = list->head->forward[0];
+ while (x != NULL) {
+ print_item(x->key, x->value);
+ x = x->forward[0];
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+skip_list_t *skip_copy_list(const skip_list_t *list)
+{
+ skip_list_t *ss = (skip_list_t *)malloc(sizeof(skip_list_t));
+ if (ss == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ ss->head = skip_make_node(list->level, NULL, NULL);
+ if (ss->head == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ss);
+ return NULL;
+ }
+
+ ss->level = list->level;
+ ss->compare_keys = list->compare_keys;
+
+ skip_node_t *x = list->head->forward[0];
+ skip_node_t *prev = list->head;
+ skip_node_t *new_prev = ss->head;
+ while (x != NULL) {
+ //print_item(x->key, x->value);
+
+ // create new node
+ skip_node_t *n = skip_make_node(list->level, x->key, x->value);
+ if (n == NULL) {
+ skip_destroy_list(&ss, NULL, NULL);
+ return NULL;
+ }
+ // set forward pointers from the previous node
+ for (int i = 0; i <= list->level; ++i) {
+ if (prev->forward[i] == x) {
+ new_prev->forward[i] = n;
+ }
+ }
+
+ prev = x;
+ x = x->forward[0];
+ new_prev = n;
+ }
+
+ return ss;
+}
diff --git a/src/common/skip-list.h b/src/common/skip-list.h
new file mode 100644
index 0000000..784f366
--- /dev/null
+++ b/src/common/skip-list.h
@@ -0,0 +1,215 @@
+/*!
+ * \file skip-list.h
+ *
+ * \author Copyright (c) 2010 the authors listed at the following URL, and/or
+ * the authors of referenced articles or incorporated external code:
+ * http://en.literateprograms.org/Skip_list_(C)?action=history&offset=20080313195128
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Generic skip-list implementation.
+ *
+ * Original retrieved from http://en.literateprograms.org/Skip_list_(C)?oldid=12811
+ * Modifications by Lubos Slovak, 2010
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+/* Copyright (c) 2010 the authors listed at the following URL, and/or
+the authors of referenced articles or incorporated external code:
+http://en.literateprograms.org/Skip_list_(C)?action=history&offset=20080313195128
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Retrieved from: http://en.literateprograms.org/Skip_list_(C)?oldid=12811
+*/
+
+#ifndef _KNOTD_COMMON_SKIP_LIST_H_
+#define _KNOTD_COMMON_SKIP_LIST_H_
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Skip list node.
+ */
+struct skip_node {
+ void *key; /*!< Key of the node. Used for ordering. */
+
+ void *value; /*!< Value stored in the node. */
+
+ /*! \brief Pointers to next item on various levels. */
+ struct skip_node **forward;
+};
+
+typedef struct skip_node skip_node_t;
+
+/*!
+ * \brief Skip list.
+ *
+ * \todo Implement quasi-randomization.
+ */
+struct skip_list {
+ /*! \brief Head of the list (with no actual key and value stored). */
+ skip_node_t *head;
+
+ /*! \brief Actual maximum level of the list. */
+ int level;
+
+ /*! \brief Function for comparing two skip list item's keys. */
+ int (*compare_keys)(void *, void *);
+};
+
+typedef struct skip_list skip_list_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates a new generic skip list.
+ *
+ * \param compare_keys Function for comparing the keys.
+ * \todo What should compare_keys exactly return?
+ *
+ * \return Pointer to the newly created skip list if successful. NULL otherwise.
+ */
+skip_list_t *skip_create_list(int (*compare_keys)(void *, void *));
+
+/*!
+ * \brief Properly destroys the list, possibly also with the keys and values.
+ *
+ * \param list Skip list to be destroyed.
+ * \param destroy_key Function for properly destroying the key. If set tu NULL,
+ * the object at which the key points will not be destroyed.
+ * \param destroy_value Function for properly destroying the key. If set tu
+ * NULL, the object at which the value points will not be
+ * destroyed.
+ */
+void skip_destroy_list(skip_list_t **list, void (*destroy_key)(void *),
+ void (*destroy_value)(void *));
+
+/*!
+ * \brief Inserts a new key-value pair into the skip list.
+ *
+ * The \a merge_values function should merge the second value to the first
+ * value. It must not delete the first value. The second value also should not
+ * be deleted (as this is concern of the caller).
+ *
+ * \param list The skip list to insert to.
+ * \param key Key of the item to be inserted. Used for ordering.
+ * \param value Value of the item to be inserted.
+ * \param merge_values Function for merging the saved values. Optional. If set
+ * to NULL, the skip list will not merge values when
+ * attempting to insert item with key already present in the
+ * list.
+ * \todo What are the function parameters and what should it
+ * return as integer?
+ *
+ * \retval 0 If successful and the key was not yet present in the list.
+ * \retval 1 If the key was already present and the new value was ignored
+ * (because no merging function was provided).
+ * \retval 2 If successful, the key was already present and the values were
+ * merged.
+ * \retval -1 If an error occured and the key was not present in the list.
+ * \retval -2 If the key is already present in the list and merging was
+ * unsuccessful.
+ */
+int skip_insert(skip_list_t *list, void *key, void *value,
+ int (*merge_values)(void **, void **));
+
+/*!
+ * \brief Removes an item with the given key from the list and optionally
+ * deletes the item's key and value.
+ *
+ * \param list Skip list to delete from.
+ * \param key Key of the item to be deleted.
+ * \param destroy_key Function for properly destroying the key. If set tu NULL,
+ * the object at which the key points will not be destroyed.
+ * \param destroy_value Function for properly destroying the key. If set tu
+ * NULL, the object at which the value points will not be
+ * destroyed.
+ *
+ * \retval 0 If successful.
+ * \retval -1 If the item was not present in the list.
+ */
+int skip_remove(skip_list_t *list, void *key, void (*destroy_key)(void *),
+ void (*destroy_value)(void *));
+
+/*!
+ * \brief Tries to find item with the given key in the list.
+ *
+ * \param list Skip list to search in.
+ * \param key Key of the item to be found.
+ *
+ * \return Value stored in the item with key \a key, or NULL if the key was not
+ * found.
+ */
+void *skip_find(const skip_list_t *list, void *key);
+
+/*!
+ * \brief Returns item with largest key smaller or equal than \a key.
+ *
+ * \param list Skip list to search in.
+ * \param key Key of the item to be found.
+ *
+ * \return Value stored in the item with largest key smaller or equal than \a
+ * key, or NULL if the key was not found.
+ */
+void *skip_find_less_or_equal(const skip_list_t *list, void *key);
+
+/*!
+ * \brief Checks if the skip list is empty.
+ *
+ * \param list Skip list to check.
+ *
+ * \retval 1 if empty.
+ * \retval 0 if non-empty.
+ */
+int skip_is_empty(const skip_list_t *list);
+
+/*!
+ * \brief Returns the first item in the skip list.
+ */
+const skip_node_t *skip_first(const skip_list_t *list);
+
+/*!
+ * \brief Returns the next item in the skip list.
+ */
+const skip_node_t *skip_next(const skip_node_t *node);
+
+/*!
+ * \brief Prints the whole list using the given print function.
+ *
+ * \param list Skip list to be printed.
+ * \param print_item Function for printing the key-value pair.
+ */
+void skip_print_list(const skip_list_t *list,
+ void (*print_item)(void *, void *));
+
+/*!
+ * \brief Copies the skip list.
+ *
+ * \param list Skip list to be copied.
+ *
+ * \return Copy of \a list.
+ *
+ * \todo Test!!!
+ */
+skip_list_t *skip_copy_list(const skip_list_t *list);
+
+#endif /* _KNOTD_COMMON_SKIP_LIST_H_ */
+
+/*! @} */
diff --git a/src/common/slab/alloc-common.h b/src/common/slab/alloc-common.h
new file mode 100644
index 0000000..32878ab
--- /dev/null
+++ b/src/common/slab/alloc-common.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file alloc-common.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Common macros for alloc.
+ *
+ * \addtogroup alloc
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_ALLOC_COMMON_H_
+#define _KNOTD_COMMON_ALLOC_COMMON_H_
+
+#include <stdio.h>
+
+//#define MEM_DEBUG
+//#define MEM_NOSLAB
+//#define MEM_POISON
+#define MEM_SLAB_CAP 5 // Cap slab_cache empty slab count (undefined = inf)
+#define MEM_COLORING // Slab cache coloring
+//#define MEM_SLAB_DEPOT // Use slab depot for slab caching (not thread-safe)
+
+/* Eliminate compiler warning with unused parameters. */
+#ifndef UNUSED
+#define UNUSED(param) (void)(param)
+#endif
+
+/* Optimisation macros. */
+#ifndef likely
+#define likely(x) __builtin_expect((x),1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect((x),0)
+#endif
+
+#ifdef MEM_DEBUG
+#define dbg_mem(msg...) fprintf(stderr, msg)
+#else
+#define dbg_mem(msg...)
+#endif
+
+
+#endif /* _KNOTD_COMMON_ALLOC_COMMON_H_ */
+
+/*! @} */
diff --git a/src/common/slab/malloc.c b/src/common/slab/malloc.c
new file mode 100644
index 0000000..ec5a68d
--- /dev/null
+++ b/src/common/slab/malloc.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+/*
+ * Skip unit if not debugging memory.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/resource.h>
+
+#include "common/slab/alloc-common.h"
+
+#ifdef MEM_DEBUG
+/*
+ * ((destructor)) attribute executes this function after main().
+ * \see http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+ */
+void __attribute__ ((destructor)) usage_dump()
+#else
+void usage_dump()
+#endif
+{
+ /* Get resource usage. */
+ struct rusage usage;
+ if (getrusage(RUSAGE_SELF, &usage) < 0) {
+ memset(&usage, 0, sizeof(struct rusage));
+ }
+
+ fprintf(stderr, "\nMemory statistics:");
+ fprintf(stderr, "\n==================\n");
+
+ fprintf(stderr, "User time: %.03lf ms\nSystem time: %.03lf ms\n",
+ usage.ru_utime.tv_sec * (double) 1000.0
+ + usage.ru_utime.tv_usec / (double)1000.0,
+ usage.ru_stime.tv_sec * (double) 1000.0
+ + usage.ru_stime.tv_usec / (double)1000.0);
+ fprintf(stderr, "Major page faults: %lu (required I/O)\nMinor page faults: %lu\n",
+ usage.ru_majflt, usage.ru_minflt);
+ fprintf(stderr, "Number of swaps: %lu\n",
+ usage.ru_nswap);
+ fprintf(stderr, "Voluntary context switches: %lu\nInvoluntary context switches: %lu\n",
+ usage.ru_nvcsw,
+ usage.ru_nivcsw);
+ fprintf(stderr, "==================\n");
+}
diff --git a/src/common/slab/malloc.h b/src/common/slab/malloc.h
new file mode 100644
index 0000000..8ca9f58
--- /dev/null
+++ b/src/common/slab/malloc.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file malloc.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Memory allocation related functions.
+ *
+ * \addtogroup alloc
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_MALLOC_H_
+#define _KNOTD_COMMON_MALLOC_H_
+
+#include <stdlib.h>
+
+/*! \brief Print usage statistics.
+ *
+ * \note This function has destructor attribute set if MEM_DEBUG is enabled.
+ *
+ * \warning Not all printed statistics are available on every OS,
+ * consult manual page for getrusage(2).
+ */
+void usage_dump();
+
+#endif // _KNOTD_COMMON_MALLOC_H_
+
+/*! @} */
diff --git a/src/common/slab/slab.c b/src/common/slab/slab.c
new file mode 100644
index 0000000..ccdf7ca
--- /dev/null
+++ b/src/common/slab/slab.c
@@ -0,0 +1,732 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#include "common/slab/alloc-common.h"
+#include "common/slab/slab.h"
+
+/*
+ * Magic constants.
+ */
+#define SLAB_MAGIC 0x51 /*!< "Sl" magic byte (slab type). */
+#define LOBJ_MAGIC 0x0B /*!< "Ob" magic byte (object type). */
+#define POISON_DWORD 0xdeadbeef /*!< Memory boundary guard magic. */
+#define SLAB_MINCOLOR 64 /*!< Minimum space reserved for cache coloring. */
+#define SLAB_HEADER sizeof(slab_t) /*!< Slab header size. */
+#define ALIGN_PTRSZ __attribute__ ((__aligned__(sizeof(void*))))
+
+/*! \brief Fast cache id lookup table.
+ *
+ * Provides O(1) lookup.
+ * Filled with interesting values from default
+ * or on-demand.
+ */
+unsigned ALIGN_PTRSZ SLAB_CACHE_LUT[SLAB_SIZE] = {
+ [24] = SLAB_GP_COUNT + 1,
+ [800] = SLAB_GP_COUNT + 2
+};
+
+/*! \brief Find the next highest power of 2. */
+static inline unsigned get_next_pow2(unsigned v)
+{
+ // Next highest power of 2
+ --v;
+ v |= v >> 1; v |= v >> 2;
+ v |= v >> 4; v |= v >> 8;
+ v |= v >> 16;
+ ++v;
+
+ return v;
+}
+
+/*! \brief Return binary logarithm of a number, which is a power of 2. */
+static inline unsigned fastlog2(unsigned v)
+{
+ // Works if we know the size is a power of 2
+ register unsigned int r = (v & 0xAAAAAAAA) != 0;
+ r |= ((v & 0xFFFF0000) != 0) << 4;
+ r |= ((v & 0xFF00FF00) != 0) << 3;
+ r |= ((v & 0xF0F0F0F0) != 0) << 2;
+ r |= ((v & 0xCCCCCCCC) != 0) << 1;
+ return r;
+}
+
+/*!
+ * \brief Fast hashing function.
+ *
+ * Finds the next highest power of 2 and returns binary logarithm.
+ * Values are stored in LUT cache for future access.
+ */
+static unsigned slab_cache_id(unsigned size)
+{
+ // Assert cache id of the smallest bufsize is 0
+ if(size <= SLAB_MIN_BUFLEN) {
+ return 0;
+ }
+
+ // Check LUT
+ unsigned id = 0;
+ if ((id = SLAB_CACHE_LUT[size])) {
+ return id;
+ } else {
+
+ // Compute binary logarithm
+ // Next highest power of 2
+ id = fastlog2(get_next_pow2(size));
+
+ // Shift cacheid of SLAB_MIN_BUFLEN to 0
+ id -= SLAB_EXP_OFFSET;
+
+ // Store
+ SLAB_CACHE_LUT[size] = id;
+ }
+
+ return id;
+}
+
+/*
+ * Slab run-time constants.
+ */
+
+size_t SLAB_MASK = 0; /*!< \brief Slab address mask (for computing offsets). */
+static unsigned SLAB_LOGSIZE = 0; /*!< \brief Binary logarithm of slab size. */
+
+/*!
+ * Depot is a caching sub-allocator of slabs.
+ * It mitigates performance impact of sequentially allocating and freeing
+ * from a slab with just a few slab items by caching N slabs before returning
+ * them to the system.
+ *
+ * \todo With wider use, locking or RCU will be necessary.
+ */
+#ifdef MEM_SLAB_DEPOT
+static slab_depot_t _depot_g; /*! \brief Global slab depot. */
+#endif // MEM_SLAB_DEPOT
+
+/*!
+ * \brief Allocate a slab of given bufsize from depot.
+ *
+ * \retval Reserved memory for slab on success.
+ * \retval NULL on errors.
+ */
+static void* slab_depot_alloc(size_t bufsize)
+{
+ void *page = 0;
+#ifdef MEM_SLAB_DEPOT
+ if (_depot_g.available) {
+ for (int i = _depot_g.available - 1; i > -1 ; --i) {
+ if(_depot_g.cache[i]->bufsize == bufsize) {
+ page = _depot_g.cache[i];
+ _depot_g.cache[i] = _depot_g.cache[--_depot_g.available];
+ return page;
+ }
+ }
+ page = _depot_g.cache[--_depot_g.available];
+ } else {
+ if(posix_memalign(&page, SLAB_SIZE, SLAB_SIZE) == 0) {
+ ((slab_t*)page)->bufsize = 0;
+ } else {
+ page = 0;
+ }
+
+ }
+#else // MEM_SLAB_DEPOT
+ if(posix_memalign(&page, SLAB_SIZE, SLAB_SIZE) == 0) {
+ ((slab_t*)page)->bufsize = 0;
+ } else {
+ page = 0;
+ }
+#endif // MEM_SLAB_DEPOT
+
+ return page;
+}
+
+/*!
+ * \brief Return a slab to the depot.
+ *
+ * \note If the depot is full, slab gets immediately freed.
+ */
+static inline void slab_depot_free(void* slab)
+{
+#ifdef MEM_SLAB_DEPOT
+ if (_depot_g.available < SLAB_DEPOT_SIZE) {
+ _depot_g.cache[_depot_g.available++] = slab;
+ } else {
+ free(slab);
+ }
+#else // MEM_SLAB_DEPOT
+ free(slab);
+#endif // MEM_SLAB_DEPOT
+}
+
+/*! \brief Initialize slab depot. */
+static void slab_depot_init()
+{
+#ifdef MEM_SLAB_DEPOT
+ _depot_g.available = 0;
+#endif // MEM_SLAB_DEPOT
+}
+
+/*! \brief Destroy slab depot. */
+static void slab_depot_destroy()
+{
+#ifdef MEM_SLAB_DEPOT
+ while(_depot_g.available) {
+ free(_depot_g.cache[--_depot_g.available]);
+ }
+#endif // MEM_SLAB_DEPOT
+}
+
+/*
+ * Initializers.
+ */
+
+/*! \brief Initializes slab subsystem (it is called automatically). */
+void __attribute__ ((constructor)) slab_init()
+{
+ // Fetch page size
+ SLAB_LOGSIZE = fastlog2(SLAB_SIZE);
+
+ // Compute slab page mask
+ SLAB_MASK = 0;
+ for (int i = 0; i < SLAB_LOGSIZE; ++i) {
+ SLAB_MASK |= 1 << i;
+ }
+ SLAB_MASK = ~SLAB_MASK;
+
+ // Initialize depot
+ slab_depot_init();
+}
+
+/*! \brief Deinitializes slab subsystem (it is called automatically). */
+void __attribute__ ((destructor)) slab_deinit()
+{
+ // Deinitialize global allocator
+ if (SLAB_LOGSIZE) {
+ slab_depot_destroy();
+ SLAB_LOGSIZE = SLAB_MASK = 0;
+ }
+}
+
+/*
+ * Cache helper functions.
+ */
+
+/* \notice Not used right now.
+static void slab_dump(slab_t* slab) {
+
+ printf("%s: buffers (bufsize=%zuB, %u/%u free): \n",
+ __func__, slab->cache->bufsize, slab->bufs_free,
+ slab->bufs_count);
+
+ void** buf = slab->head;
+ int i = 0, n = 0;
+ while(buf != 0) {
+ size_t diff = (size_t)((char*)buf - (char*)slab->base);
+ printf("-> %lu", diff / slab->cache->bufsize);
+ buf = (void**)(*buf);
+ if (++i == 10) {
+ printf("\n");
+ i = 0;
+ }
+ ++n;
+ }
+
+ printf("\n");
+}
+*/
+
+/*!
+ * \brief Free all slabs from a slab cache.
+ * \return Number of freed slabs.
+ */
+static inline int slab_cache_free_slabs(slab_t* slab)
+{
+ int count = 0;
+ while (slab) {
+ slab_t* next = slab->next;
+ slab_destroy(&slab);
+ ++count;
+ slab = next;
+
+ }
+ return count;
+}
+
+/*
+ * Slab helper functions.
+ */
+
+/*! \brief Return number of slabs in a linked list. */
+static inline unsigned slab_list_walk(slab_t* slab)
+{
+ unsigned count = 0;
+ while(slab) {
+ slab = slab->next;
+ ++count;
+ }
+ return count;
+}
+
+/*! \brief Remove slab from a linked list. */
+static void slab_list_remove(slab_t* slab)
+{
+ // Disconnect from list
+ if (slab->prev) {
+ slab->prev->next = slab->next;
+ }
+ if(slab->next) {
+ slab->next->prev = slab->prev;
+ }
+
+ // Disconnect from cache
+ slab_cache_t* cache = slab->cache;
+ {
+ if (cache->slabs_free == slab) {
+ cache->slabs_free = slab->next;
+ } else if (cache->slabs_full == slab) {
+ cache->slabs_full = slab->next;
+ }
+ }
+}
+
+/*! \brief Insert slab into a linked list. */
+static void slab_list_insert(slab_t** list, slab_t* item)
+{
+ // If list exists, push to the top
+ item->prev = 0;
+ item->next = *list;
+ if(*list) {
+ (*list)->prev = item;
+ }
+ *list = item;
+}
+
+/*! \brief Move slab from one linked list to another. */
+static inline void slab_list_move(slab_t** target, slab_t* slab)
+{
+ slab_list_remove(slab);
+ slab_list_insert(target, slab);
+}
+
+/*
+ * API functions.
+ */
+
+slab_t* slab_create(slab_cache_t* cache)
+{
+ const size_t size = SLAB_SIZE;
+
+ slab_t* slab = slab_depot_alloc(cache->bufsize);
+
+ if (unlikely(slab < 0)) {
+ dbg_mem("%s: failed to allocate aligned memory block\n",
+ __func__);
+ return 0;
+ }
+
+ /* Initialize slab. */
+ slab->magic = SLAB_MAGIC;
+ slab->cache = cache;
+ slab_list_insert(&cache->slabs_free, slab);
+#ifdef MEM_SLAB_CAP
+ ++cache->empty;
+#endif
+
+ /* Already initialized? */
+ if (slab->bufsize == cache->bufsize) {
+ return slab;
+ } else {
+ slab->bufsize = cache->bufsize;
+ }
+
+ /* Ensure the item size can hold at least a size of ptr. */
+ size_t item_size = slab->bufsize;
+ if (unlikely(item_size < SLAB_MIN_BUFLEN)) {
+ item_size = SLAB_MIN_BUFLEN;
+ }
+
+ /* Ensure at least some space for coloring */
+ size_t data_size = size - sizeof(slab_t);
+#ifdef MEM_COLORING
+ size_t free_space = data_size % item_size;
+ if (unlikely(free_space < SLAB_MINCOLOR)) {
+ free_space = SLAB_MINCOLOR;
+ }
+
+
+ /// unsigned short color = __sync_fetch_and_add(&cache->color, 1);
+ unsigned short color = (cache->color += sizeof(void*));
+ color = color % free_space;
+#else
+ const unsigned short color = 0;
+#endif
+
+ /* Calculate useable data size */
+ data_size -= color;
+ slab->bufs_count = data_size / item_size;
+ slab->bufs_free = slab->bufs_count;
+
+ // Save first item as next free
+ slab->base = (char*)slab + sizeof(slab_t) + color;
+ slab->head = (void**)slab->base;
+
+ // Create freelist, skip last member, which is set to NULL
+ char* item = (char*)slab->head;
+ for(unsigned i = 0; i < slab->bufs_count - 1; ++i) {
+ *((void**)item) = item + item_size;
+ item += item_size;
+ }
+
+ // Set last buf to NULL (tail)
+ *((void**)item) = (void*)0;
+
+ // Ensure the last item has a NULL next
+ dbg_mem("%s: created slab (%p, %p) (%zu B)\n",
+ __func__, slab, slab + size, size);
+ return slab;
+}
+
+void slab_destroy(slab_t** slab)
+{
+ /* Disconnect from the list */
+ slab_list_remove(*slab);
+
+ /* Free slab */
+ slab_depot_free(*slab);
+
+ /* Invalidate pointer. */
+ dbg_mem("%s: deleted slab %p\n", __func__, *slab);
+ *slab = 0;
+}
+
+void* slab_alloc(slab_t* slab)
+{
+ // Fetch first free item
+ void **item = 0;
+ {
+ if((item = slab->head)) {
+ slab->head = (void**)*item;
+ --slab->bufs_free;
+ } else {
+ // No more free items
+ return 0;
+ }
+ }
+
+#ifdef MEM_DEBUG
+ // Increment statistics
+ __sync_add_and_fetch(&slab->cache->stat_allocs, 1);
+#endif
+
+ // Move to full?
+ if (unlikely(slab->bufs_free == 0)) {
+ slab_list_move(&slab->cache->slabs_full, slab);
+ } else {
+#ifdef MEM_SLAB_CAP
+ // Mark not empty?
+ if (unlikely(slab->bufs_free == slab->bufs_count - 1)) {
+ --slab->cache->empty;
+ }
+#endif
+ }
+
+ return item;
+}
+
+void slab_free(void* ptr)
+{
+ // Null pointer check
+ if (unlikely(!ptr)) {
+ return;
+ }
+
+ // Get slab start address
+ slab_t* slab = slab_from_ptr(ptr);
+ assert(slab);
+
+ // Check if it exists in directory
+ if (slab->magic == SLAB_MAGIC) {
+
+ // Return buf to slab
+ *((void**)ptr) = (void*)slab->head;
+ slab->head = (void**)ptr;
+ ++slab->bufs_free;
+
+#ifdef MEM_DEBUG
+ // Increment statistics
+ __sync_add_and_fetch(&slab->cache->stat_frees, 1);
+#endif
+
+ // Return to partial
+ if(unlikely(slab->bufs_free == 1)) {
+ slab_list_move(&slab->cache->slabs_free, slab);
+ } else {
+#ifdef MEM_SLAB_CAP
+ // Recycle if empty
+ if(unlikely(slab_isempty(slab))) {
+ if(slab->cache->empty == MEM_SLAB_CAP) {
+ slab_destroy(&slab);
+ } else {
+ ++slab->cache->empty;
+ }
+ }
+#endif
+ }
+
+ } else {
+
+ // Pointer is not a slab
+ // Presuming it's a large block
+ slab_obj_t* bs = (slab_obj_t*)ptr - 1;
+
+#ifdef MEM_POISON
+ // Remove memory barrier
+ mprotect(ptr + bs->size, sizeof(int), PROT_READ|PROT_WRITE);
+#endif
+
+ // Unmap
+ dbg_mem("%s: unmapping large block of %zu bytes at %p\n",
+ __func__, bs->size, ptr);
+ free(bs);
+ }
+}
+
+int slab_cache_init(slab_cache_t* cache, size_t bufsize)
+{
+ if (unlikely(!bufsize)) {
+ return -1;
+ }
+
+ cache->empty = 0;
+ cache->bufsize = bufsize;
+ cache->slabs_free = cache->slabs_full = 0;
+ cache->color = 0;
+
+ /* Initialize stats */
+ cache->stat_allocs = cache->stat_frees = 0;
+
+ dbg_mem("%s: created cache of size %zu\n",
+ __func__, bufsize);
+
+ return 0;
+}
+
+void slab_cache_destroy(slab_cache_t* cache) {
+
+ // Free slabs
+ unsigned free_s = slab_cache_free_slabs(cache->slabs_free);
+ unsigned full_s = slab_cache_free_slabs(cache->slabs_full);
+#ifndef MEM_DEBUG
+ UNUSED(free_s);
+ UNUSED(full_s);
+#else
+ dbg_mem("%s: %u empty/partial, %u full caches\n",
+ __func__, free_s, full_s);
+#endif
+
+ // Invalidate cache
+ cache->bufsize = 0;
+ cache->slabs_free = cache->slabs_full = 0;
+}
+
+void* slab_cache_alloc(slab_cache_t* cache)
+{
+ slab_t* slab = cache->slabs_free;
+ if(!cache->slabs_free) {
+ slab = slab_create(cache);
+ if (slab == NULL) {
+ return NULL;
+ }
+ }
+
+
+ return slab_alloc(slab);
+}
+
+int slab_cache_reap(slab_cache_t* cache)
+{
+ // For now, just free empty slabs
+ slab_t* slab = cache->slabs_free;
+ int count = 0;
+ while (slab) {
+ slab_t* next = slab->next;
+ if (slab_isempty(slab)) {
+ slab_destroy(&slab);
+ ++count;
+ }
+ slab = next;
+
+ }
+
+ cache->empty = 0;
+ return count;
+}
+
+int slab_alloc_init(slab_alloc_t* alloc)
+{
+ // Invalidate
+ memset(alloc, 0, sizeof(slab_alloc_t));
+
+ // Initialize descriptors cache
+ slab_cache_init(&alloc->descriptors, sizeof(slab_cache_t));
+
+ return 0;
+}
+
+void slab_alloc_destroy(slab_alloc_t* alloc)
+{
+ // Destroy all caches
+ for (unsigned i = 0; i < SLAB_CACHE_COUNT; ++i) {
+ if (alloc->caches[i] != 0) {
+ slab_cache_destroy(alloc->caches[i]);
+ }
+ }
+
+ // Destroy cache for descriptors
+ slab_cache_destroy(&alloc->descriptors);
+}
+
+void* slab_alloc_alloc(slab_alloc_t* alloc, size_t size)
+{
+ // Invalid size check
+ if (unlikely(!size)) {
+ return 0;
+ }
+
+#ifdef MEM_POISON
+ // Reserve memory for poison
+ size += sizeof(int);
+#endif
+ // Directly map large block
+ if (unlikely(size > SLAB_SIZE/2)) {
+
+ // Map block
+ size += sizeof(slab_obj_t);
+ slab_obj_t* p = 0;
+ p = malloc(size);
+
+ dbg_mem("%s: mapping large block of %zu bytes at %p\n",
+ __func__, size, p + 1);
+
+ /* Initialize. */
+ p->magic = LOBJ_MAGIC;
+ p->size = size - sizeof(slab_obj_t);
+
+#ifdef MEM_POISON
+ // Reduce real size
+ p->size -= sizeof(int);
+
+ // Memory barrier
+ int* pb = (int*)((char*)p + size - sizeof(int));
+ *pb = POISON_DWORD;
+ mprotect(pb, sizeof(int), PROT_NONE);
+#endif
+
+ return p + 1;
+ }
+
+ // Get cache id from size
+ unsigned cache_id = slab_cache_id(size);
+
+ // Check if associated cache exists
+ if (unlikely(alloc->caches[cache_id] == 0)) {
+
+ // Assert minimum cache size
+ if (unlikely(size < SLAB_MIN_BUFLEN)) {
+ size = SLAB_MIN_BUFLEN;
+ }
+
+ // Calculate cache bufsize
+ size_t bufsize = size;
+ if (cache_id < SLAB_GP_COUNT) {
+ bufsize = get_next_pow2(size);
+ }
+
+ // Create cache
+ dbg_mem("%s: creating cache of %zuB (req. %zuB) (id=%u)\n",
+ __func__, bufsize, size, cache_id);
+
+ slab_cache_t* cache = slab_cache_alloc(&alloc->descriptors);
+ slab_cache_init(cache, bufsize);
+ alloc->caches[cache_id] = cache;
+ }
+
+ // Allocate from cache
+ void* mem = slab_cache_alloc(alloc->caches[cache_id]);
+
+#ifdef MEM_POISON
+ // Memory barrier
+ /*! \todo Broken, need to store the barrier byte size. */
+ //int* pb = (int*)((char*)mem + size - sizeof(int));
+ //mprotect(pb, sizeof(int), PROT_NONE);
+#endif
+ return mem;
+}
+
+void *slab_alloc_realloc(slab_alloc_t* alloc, void *ptr, size_t size)
+{
+ // realloc(0) equals to free(ptr)
+ if (!size) {
+ slab_free(ptr);
+ return 0;
+ }
+
+ // Allocate new buf
+ void *nptr = slab_alloc_alloc(alloc, size);
+ assert(nptr);
+
+ // Copy memory if present
+ if (ptr) {
+ slab_t* slab = slab_from_ptr(ptr);
+ memcpy(nptr, ptr, slab->cache->bufsize);
+
+ // Free old buf
+ slab_free(ptr);
+ }
+
+ return nptr;
+}
+
+void slab_alloc_stats(slab_alloc_t* alloc)
+{
+#ifdef MEM_DEBUG
+ printf("Cache usage:\n");
+ for (int i = 0; i < SLAB_CACHE_COUNT; ++i) {
+
+ if (!alloc->caches[i])
+ continue;
+
+ slab_cache_t* cache = alloc->caches[i];
+ unsigned free_s = slab_list_walk(cache->slabs_free);
+ unsigned full_s = slab_list_walk(cache->slabs_full);
+ printf("%4zu: allocs=%lu frees=%lu "
+ "(%u empty+partial, %u full)\n",
+ cache->bufsize, cache->stat_allocs,
+ cache->stat_frees, free_s, full_s);
+ }
+#else
+ printf("Cache usage: not available, enable MEM_DEBUG and recompile.\n");
+#endif
+}
+
diff --git a/src/common/slab/slab.h b/src/common/slab/slab.h
new file mode 100644
index 0000000..d64188e
--- /dev/null
+++ b/src/common/slab/slab.h
@@ -0,0 +1,353 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file slab.h
+ *
+ * \author Marek Vavrusa <marek.vavusa@nic.cz>
+ *
+ * \brief SLAB allocator.
+ *
+ * SLAB cache works with either custom SLAB sizes and
+ * Next-Highest-Power-Of-2 sizes.
+ *
+ * Slab size is a multiple of PAGE_SIZE and uses
+ * system allocator for larger blocks.
+ *
+ * Allocated SLABs are PAGE_SIZE aligned for a fast O(1)
+ * address-from-item lookup. This results in nearly none memory
+ * overhead for a very small blocks (<64B), but it requires the
+ * underlying allocator to be effective in allocating page size aligned memory
+ * as well. The major disadvantage is that each Slab must be aligned to it's
+ * size as opposed to boundary tags.
+ *
+ * Slab implements simple coloring mechanism to improve
+ * cache line utilisation.
+ *
+ * \ref SLAB_SIZE is a fixed size of a slab. As a rule of thumb, the slab is
+ * effective when the maximum allocated block size is below 1/4 of a SLAB_SIZE.
+ * f.e. 16kB SLAB is most effective up to 4kB block size.
+ *
+ * \ref MEM_POISON flag enables checking read/writes after the allocated memory
+ * and segmentation fault. This poses a significant time and space overhead.
+ * Enable only when debugging.
+ *
+ * \ref MEM_SLAB_CAP defines a maximum limit of a number of empty slabs that a cache
+ * can keep at a time. This results in a slight performance regression,
+ * but actively recycles unuse memory.
+ *
+ * \ref MEM_DEPOT_COUNT defines how many recycled slabs will be cached for a later
+ * use instead of returning them immediately to the OS. This significantly
+ * reduces a number of syscalls in some cases.
+ * f.e. 16 means 16 * SLAB_SIZE cache, for 16kB slabs = 256kB cache
+ *
+ * \ref MEM_COLORING enables simple cache coloring. This is generally a useful
+ * feature since all slabs are page size aligned and
+ * (depending on architecture) this slightly improves performance
+ * and cacheline usage at the cost of a minimum of 64 bytes per slab of
+ * overhead. Undefine MEM_COLORING in common.h to disable coloring.
+ *
+ * Optimal usage for a specific behavior (similar allocation sizes):
+ * \code
+ * slab_cache_t cache;
+ * slab_cache_init(&cache, N); // Initialize, N means cache chunk size
+ * ...
+ * void* mem = slab_cache_alloc(&cache); // Allocate N bytes
+ * ...
+ * slab_free(mem); // Recycle memory
+ * ...
+ * slab_cache_destroy(&cache); // Deinitialize cache
+ * \endcode
+ *
+ *
+ * \todo Allocate slab headers elsewhere and use just first sizeof(void*) bytes
+ * in each slab as a pointer to slab header. This could improve the
+ * performance.
+ *
+ * \note Slab allocation is not thread safe for performance reasons.
+ *
+ * \addtogroup alloc
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_SLAB_H_
+#define _KNOTD_COMMON_SLAB_H_
+
+#include <pthread.h>
+#include <stdint.h>
+
+/* Constants. */
+#define SLAB_SIZE (4096*4) //!< Slab size (16K blocks)
+#define SLAB_MIN_BUFLEN 8 //!< Minimal allocation block size is 8B.
+#define SLAB_EXP_OFFSET 3 //!< Minimal allocation size is 8B = 2^3, exp is 3.
+#define SLAB_GP_COUNT 10 //!< General-purpose caches count.
+#define SLAB_US_COUNT 10 //!< User-specified caches count.
+#define SLAB_DEPOT_SIZE 16 //!< N slabs cached = N*SLAB_SIZE kB cap
+#define SLAB_CACHE_COUNT (SLAB_GP_COUNT + SLAB_US_COUNT) //!< Slab cache count.
+struct slab_cache_t;
+
+/* Macros. */
+
+/*! \brief Return slab base address from pointer. */
+#define slab_from_ptr(p) ((void*)((size_t)(p) & SLAB_MASK))
+
+/*! \brief Return true if slab is empty. */
+#define slab_isempty(s) ((s)->bufs_free == (s)->bufs_count)
+
+/*!
+ * \brief Slab descriptor.
+ *
+ * Slab is a block of memory used for an allocation of
+ * smaller objects (bufs) later on.
+ * Each slab is currently aligned to page size to easily
+ * determine slab address from buf pointer.
+ *
+ * \warning Do not use slab_t directly as it cannot grow, see slab_cache_t.
+ */
+typedef struct slab_t {
+ char magic; /*!< Identifies memory block type. */
+ unsigned short bufsize; /*!< Slab bufsize. */
+ struct slab_cache_t *cache; /*!< Owner cache. */
+ struct slab_t *prev, *next; /*!< Neighbours in slab lists. */
+ unsigned bufs_count; /*!< Number of bufs in slab. */
+ unsigned bufs_free; /*!< Number of available bufs. */
+ void **head; /*!< Pointer to first available buf. */
+ char* base; /*!< Base address for bufs. */
+} slab_t;
+
+/*!
+ * \brief Slab depot.
+ *
+ * To mitigate slab initialization costs, depot keeps a finite number of
+ * stacked slabs before returning them to the system.
+ */
+typedef struct slab_depot_t {
+ size_t available; /*!< Number of available pages. */
+ slab_t* cache[SLAB_DEPOT_SIZE]; /*!< Stack of free slabs. */
+} slab_depot_t;
+
+/*!
+ * \brief Large object descriptor.
+ *
+ * Large object differs from slab with magic byte and
+ * contains object size.
+ *
+ * Magic needs to be first to overlap with slab_t magic byte.
+ */
+typedef struct slab_obj_t {
+ char magic; /*!< Identifies memory block type. */
+ size_t size; /*!< Object size. */
+} slab_obj_t;
+
+/*!
+ * \brief Slab cache descriptor.
+ *
+ * Slab cache is a list of 0..n slabs with the same buf size.
+ * It is responsible for slab state keeping.
+ *
+ * Once a slab is created, it is moved to free list.
+ * When it is full, it is moved to full list.
+ * Once a buf from full slab is freed, the slab is moved to
+ * free list again (there may be some hysteresis for mitigating
+ * a sequential alloc/free).
+ *
+ * Allocation of new slabs is on-demand, empty slabs are reused if possible.
+ *
+ * \note Slab implementation is different from Bonwick (Usenix 2001)
+ * http://www.usenix.org/event/usenix01/bonwick.html
+ * as it doesn't feature empty and partial list.
+ * This is due to fact, that user space allocator rarely
+ * needs to count free slabs. There is no way the OS could
+ * notify the application, that the memory is scarce.
+ * A slight performance increased is measured in benchmark.
+ *
+ * \note Statistics are only available if MEM_DEBUG is enabled.
+ */
+typedef struct slab_cache_t {
+ unsigned short color; /*!< Current cache color. */
+ unsigned short empty; /*!< Number of empty slabs. */
+ size_t bufsize; /*!< Cache object (buf) size. */
+ slab_t *slabs_free; /*!< List of free slabs. */
+ slab_t *slabs_full; /*!< List of full slabs. */
+
+ /* Statistics. */
+ unsigned long stat_allocs; /*!< Allocation count. */
+ unsigned long stat_frees; /*!< Free count. */
+} slab_cache_t;
+
+/*!
+ * \brief Slab allocator descriptor.
+ *
+ * \note For a number of slab caches, consult SLAB_GP_COUNT
+ * and a number of specific records in SLAB_CACHE_LUT lookup table.
+ *
+ * \warning It is currently not advised to use this general purpose allocator,
+ * as it usually doesn't yield an expected performance for higher
+ * bookkeeping costs and it also depends on the allocation behavior
+ * as well. Look for slab_cache for a specialized use in most cases.
+ */
+typedef struct slab_alloc_t {
+ slab_cache_t descriptors; /*!< Slab cache for cache descriptors. */
+ slab_cache_t* caches[SLAB_CACHE_COUNT]; /*!< Number of slab caches. */
+} slab_alloc_t;
+
+/*!
+ * \brief Create a slab of predefined size.
+ *
+ * At the moment, slabs are equal to page size and page size aligned.
+ * This enables quick and efficient buf to slab lookup by pointer arithmetic.
+ *
+ * Slab uses simple coloring scheme with and the memory block is always
+ * sizeof(void*) aligned.
+ *
+ * \param cache Parent cache.
+ * \retval Slab instance on success.
+ * \retval NULL on error.
+ */
+slab_t* slab_create(slab_cache_t* cache);
+
+/*!
+ * \brief Destroy slab instance.
+ *
+ * Slab is disconnected from any list and freed.
+ * Dereferenced slab parameter is set to NULL.
+ *
+ * \param slab Pointer to given slab.
+ */
+void slab_destroy(slab_t** slab);
+
+/*!
+ * \brief Allocate a buf from slab.
+ *
+ * Returns a pointer to allocated memory or NULL on error.
+ *
+ * \param slab Given slab instance.
+ * \retval Pointer to allocated memory.
+ * \retval NULL on error.
+ */
+void* slab_alloc(slab_t* slab);
+
+/*!
+ * \brief Recycle memory.
+ *
+ * Given memory is returned to owner slab.
+ * Memory content may be rewritten.
+ *
+ * \param ptr Returned memory.
+ */
+void slab_free(void* ptr);
+
+/*!
+ * \brief Create a slab cache.
+ *
+ * Create a slab cache with no allocated slabs.
+ * Slabs are allocated on-demand.
+ *
+ * \param cache Pointer to uninitialized cache.
+ * \param bufsize Single item size for later allocs.
+ * \retval 0 on success.
+ * \retval -1 on error;
+ */
+int slab_cache_init(slab_cache_t* cache, size_t bufsize);
+
+/*!
+ * \brief Destroy a slab cache.
+ *
+ * Destroy a slab cache and all associated slabs.
+ *
+ * \param cache Pointer to slab cache.
+ */
+void slab_cache_destroy(slab_cache_t* cache);
+
+/*!
+ * \brief Allocate from the cache.
+ *
+ * It tries to use partially free caches first,
+ * empty caches second and allocates a new cache
+ * as a last resort.
+ *
+ * \param cache Given slab cache.
+ * \retval Pointer to allocated memory.
+ * \retval NULL on error.
+ */
+void* slab_cache_alloc(slab_cache_t* cache);
+
+/*!
+ * \brief Free unused slabs from cache.
+ *
+ * \param cache Given slab cache.
+ * \return Number of freed slabs.
+ */
+int slab_cache_reap(slab_cache_t* cache);
+
+/*!
+ * \brief Create a general purpose slab allocator.
+ *
+ * \note Please consult struct slab_alloc_t for performance hints.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int slab_alloc_init(slab_alloc_t* alloc);
+
+/*!
+ * \brief Delete slab allocator.
+ *
+ * This destroys all associated caches and frees memory.
+ *
+ * \param alloc Given allocator instance.
+ */
+void slab_alloc_destroy(slab_alloc_t* alloc);
+
+/*!
+ * \brief Allocate a block of memory.
+ *
+ * Returns a block of allocated memory.
+ *
+ * \note At least SLAB_MIN_BUFSIZE bytes is allocated.
+ *
+ * \note Please consult struct slab_alloc_t for performance hints.
+ *
+ * \param alloc Allocator instance.
+ * \param size Requested block size.
+ * \retval Pointer to allocated memory.
+ * \retval NULL on error.
+ */
+void* slab_alloc_alloc(slab_alloc_t* alloc, size_t size);
+
+/*!
+ * \brief Reallocate data from one slab to another.
+ *
+ * \param alloc Allocator instance.
+ * \param ptr Pointer to allocated memory.
+ * \param size Requested memory block size.
+ * \retval Pointer to newly allocated memory.
+ * \retval NULL on error.
+ *
+ * \todo Realloc could be probably implement more effectively.
+ */
+void *slab_alloc_realloc(slab_alloc_t* alloc, void *ptr, size_t size);
+
+/*!
+ *
+ * \brief Dump allocator stats.
+ *
+ * \param alloc Allocator instance.
+ */
+void slab_alloc_stats(slab_alloc_t* alloc);
+
+#endif /* _KNOTD_COMMON_SLAB_H_ */
+
+/*! @} */
diff --git a/src/common/sockaddr.c b/src/common/sockaddr.c
new file mode 100644
index 0000000..cd3a4b9
--- /dev/null
+++ b/src/common/sockaddr.c
@@ -0,0 +1,174 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "common/sockaddr.h"
+
+int sockaddr_init(sockaddr_t *addr, int af)
+{
+ /* Reset pointer. */
+ memset(addr, 0, sizeof(sockaddr_t));
+ addr->family = -1;
+
+ /* Initialize address size. */
+ switch(af) {
+ case AF_INET:
+ addr->len = sizeof(struct sockaddr_in);
+ break;
+#ifndef DISABLE_IPV6
+ case AF_INET6:
+ addr->len = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ /* Update pointer. */
+ addr->family = af;
+ return sockaddr_update(addr);
+}
+
+int sockaddr_update(sockaddr_t *addr)
+{
+ /* Update internal pointer. */
+ switch(addr->len) {
+ case sizeof(struct sockaddr_in):
+ addr->ptr = (struct sockaddr*)&addr->addr4;
+ break;
+#ifndef DISABLE_IPV6
+ case sizeof(struct sockaddr_in6):
+ addr->ptr = (struct sockaddr*)&addr->addr6;
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int sockaddr_set(sockaddr_t *dst, int family, const char* addr, int port)
+{
+ if (!dst || !addr || port < 0) {
+ return -1;
+ }
+
+ /* Initialize. */
+ dst->family = -1;
+ dst->ptr = 0;
+ dst->len = 0;
+ sockaddr_init(dst, family);
+
+ /* Initialize depending on address family. */
+ void *paddr = 0;
+ switch(family) {
+ case AF_INET:
+ dst->addr4.sin_family = family;
+ dst->addr4.sin_port = htons(port);
+ paddr = &dst->addr4.sin_addr;
+ dst->addr4.sin_addr.s_addr = INADDR_ANY;
+ break;
+#ifndef DISABLE_IPV6
+ case AF_INET6:
+ dst->addr6.sin6_family = family;
+ dst->addr6.sin6_port = htons(port);
+ paddr = &dst->addr6.sin6_addr;
+ memcpy(&dst->addr6.sin6_addr,
+ &in6addr_any, sizeof(in6addr_any));
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ /* Convert address. */
+ return inet_pton(family, addr, paddr);
+}
+
+int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size)
+{
+ if (!addr || !dst || size == 0) {
+ return -1;
+ }
+
+ /* Minimum length. */
+ size_t minlen = INET_ADDRSTRLEN;
+
+ /* Check unsupported IPv6. */
+#ifdef DISABLE_IPV6
+ if (addr->family == AF_INET6) {
+ return -1;
+ }
+#else
+ minlen = INET6_ADDRSTRLEN;
+#endif
+
+ /* Check minimum length. */
+ if (size < minlen) {
+ return -1;
+ }
+
+ /* Convert. */
+#ifdef DISABLE_IPV6
+ dst[0] = '\0';
+#else
+ /* Load IPv6 addr if default. */
+ if (addr->family == AF_INET6) {
+ inet_ntop(addr->family, &addr->addr6.sin6_addr,
+ dst, size);
+ }
+#endif
+ /* Load IPv4 if set. */
+ if (addr->family == AF_INET) {
+ inet_ntop(addr->family, &addr->addr4.sin_addr,
+ dst, size);
+ }
+
+ return 0;
+}
+
+int sockaddr_portnum(sockaddr_t *addr)
+{
+ if (!addr) {
+ return -1;
+ }
+
+ switch(addr->family) {
+
+ /* IPv4 */
+ case AF_INET:
+ return ntohs(addr->addr4.sin_port);
+ break;
+
+ /* IPv6 */
+#ifndef DISABLE_IPV6
+ case AF_INET6:
+ return ntohs(addr->addr6.sin6_port);
+ break;
+#endif
+
+ /* N/A */
+ default:
+ return -1;
+ break;
+ }
+}
diff --git a/src/common/sockaddr.h b/src/common/sockaddr.h
new file mode 100644
index 0000000..51ba779
--- /dev/null
+++ b/src/common/sockaddr.h
@@ -0,0 +1,120 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file sockaddr.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Socket address abstraction layer.
+ *
+ * \addtogroup common_lib
+ * @{
+ */
+
+#ifndef _KNOTD_SOCKADDR_H_
+#define _KNOTD_SOCKADDR_H_
+
+/* BSD IPv6 */
+#ifndef __POSIX_VISIBLE
+#define __POSIX_VISIBLE = 200112
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/*! \brief Universal socket address. */
+typedef struct sockaddr_t {
+ int family; /*!< Address family. */
+ struct sockaddr* ptr; /*!< Pointer to used sockaddr. */
+ socklen_t len; /*!< Length of used sockaddr. */
+ union {
+ struct sockaddr_in addr4; /*!< IPv4 sockaddr. */
+#ifndef DISABLE_IPV6
+ struct sockaddr_in6 addr6; /*!< IPv6 sockaddr. */
+#endif
+ };
+} sockaddr_t;
+
+/*! \brief Maximum address length in string format. */
+#ifdef DISABLE_IPV6
+#define SOCKADDR_STRLEN INET_ADDRSTRLEN
+#else
+#define SOCKADDR_STRLEN INET6_ADDRSTRLEN
+#endif
+
+/*!
+ * \brief Initialize address structure.
+ *
+ * Members ptr and len will be initialized to correct address family.
+ *
+ * \param addr Socket address structure.
+ * \param af Requested address family.
+ *
+ * \retval 0 on success.
+ * \retval -1 on unsupported address family (probably INET6).
+ */
+int sockaddr_init(sockaddr_t *addr, int af);
+
+/*!
+ * \brief Update internal pointers according to length.
+ *
+ * \param addr Socket address structure.
+ *
+ * \retval 0 on success.
+ * \retval -1 on invalid size.
+ */
+int sockaddr_update(sockaddr_t *addr);
+
+/*!
+ * \brief Set address and port.
+ *
+ * \param dst Target address structure.
+ * \param family Address family.
+ * \param addr IP address in string format.
+ * \param port Port.
+ *
+ * \retval 0 if addr is not valid address in string format.
+ * \retval positive value in case of success.
+ * \retval -1 on error.
+ * \see inet_pton(3)
+ */
+int sockaddr_set(sockaddr_t *dst, int family, const char* addr, int port);
+
+/*!
+ * \brief Return string representation of socket address.
+ *
+ * \param addr Socket address structure.
+ * \param dst Destination for string representation.
+ * \param size Maximum number of written bytes.
+ *
+ * \retval 0 on success.
+ * \retval -1 on invalid parameters.
+ */
+int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size);
+
+/*!
+ * \brief Return port number from address.
+ *
+ * \param addr Socket address structure.
+ *
+ * \retval Port number on success.
+ * \retval -1 on errors.
+ */
+int sockaddr_portnum(sockaddr_t *addr);
+
+#endif /* _KNOTD_SOCKADDR_H_ */
+
+/*! @} */
diff --git a/src/common/tree.h b/src/common/tree.h
new file mode 100644
index 0000000..efea65b
--- /dev/null
+++ b/src/common/tree.h
@@ -0,0 +1,268 @@
+/* tree.h -- AVL trees (in the spirit of BSD's 'queue.h') -*- C -*- */
+
+/* Copyright (c) 2005 Ian Piumarta
+ *
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the 'Software'), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * provided that the above copyright notice(s) and this permission notice appear
+ * in all copies of the Software and that both the above copyright notice(s) and
+ * this permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
+ */
+
+/* This file defines an AVL balanced binary tree [Georgii M. Adelson-Velskii and
+ * Evgenii M. Landis, 'An algorithm for the organization of information',
+ * Doklady Akademii Nauk SSSR, 146:263-266, 1962 (Russian). Also in Myron
+ * J. Ricci (trans.), Soviet Math, 3:1259-1263, 1962 (English)].
+ *
+ * An AVL tree is headed by pointers to the root node and to a function defining
+ * the ordering relation between nodes. Each node contains an arbitrary payload
+ * plus three fields per tree entry: the depth of the subtree for which it forms
+ * the root and two pointers to child nodes (singly-linked for minimum space, at
+ * the expense of direct access to the parent node given a pointer to one of the
+ * children). The tree is rebalanced after every insertion or removal. The
+ * tree may be traversed in two directions: forward (in-order left-to-right) and
+ * reverse (in-order, right-to-left).
+ *
+ * Because of the recursive nature of many of the operations on trees it is
+ * necessary to define a number of helper functions for each type of tree node.
+ * The macro TREE_DEFINE(node_tag, entry_name) defines these functions with
+ * unique names according to the node_tag. This macro should be invoked,
+ * thereby defining the necessary functions, once per node tag in the program.
+ *
+ * For details on the use of these macros, see the tree(3) manual page.
+ */
+
+/* Downloaded from http://piumarta.com/software/tree/ */
+
+#ifndef __tree_h
+#define __tree_h
+
+
+#define TREE_DELTA_MAX 1
+
+#define TREE_ENTRY(type) \
+ struct { \
+ struct type *avl_left; \
+ struct type *avl_right; \
+ int avl_height; \
+ }
+
+#define TREE_HEAD(name, type) \
+ struct name { \
+ struct type *th_root; \
+ int (*th_cmp)(struct type *lhs, struct type *rhs); \
+ }
+
+#define TREE_INITIALIZER(cmp) { 0, cmp }
+
+#define TREE_DELTA(self, field) \
+ (( (((self)->field.avl_left) ? (self)->field.avl_left->field.avl_height : 0)) \
+ - (((self)->field.avl_right) ? (self)->field.avl_right->field.avl_height : 0))
+
+/* Recursion prevents the following from being defined as macros. */
+
+#define TREE_DEFINE(node, field) \
+ \
+ struct node *TREE_BALANCE_##node##_##field(struct node *); \
+ \
+ struct node *TREE_ROTL_##node##_##field(struct node *self) \
+ { \
+ struct node *r= self->field.avl_right; \
+ self->field.avl_right= r->field.avl_left; \
+ r->field.avl_left= TREE_BALANCE_##node##_##field(self); \
+ return TREE_BALANCE_##node##_##field(r); \
+ } \
+ \
+ struct node *TREE_ROTR_##node##_##field(struct node *self) \
+ { \
+ struct node *l= self->field.avl_left; \
+ self->field.avl_left= l->field.avl_right; \
+ l->field.avl_right= TREE_BALANCE_##node##_##field(self); \
+ return TREE_BALANCE_##node##_##field(l); \
+ } \
+ \
+ struct node *TREE_BALANCE_##node##_##field(struct node *self) \
+ { \
+ int delta= TREE_DELTA(self, field); \
+ \
+ if (delta < -TREE_DELTA_MAX) \
+ { \
+ if (TREE_DELTA(self->field.avl_right, field) > 0) \
+ self->field.avl_right= TREE_ROTR_##node##_##field(self->field.avl_right); \
+ return TREE_ROTL_##node##_##field(self); \
+ } \
+ else if (delta > TREE_DELTA_MAX) \
+ { \
+ if (TREE_DELTA(self->field.avl_left, field) < 0) \
+ self->field.avl_left= TREE_ROTL_##node##_##field(self->field.avl_left); \
+ return TREE_ROTR_##node##_##field(self); \
+ } \
+ self->field.avl_height= 0; \
+ if (self->field.avl_left && (self->field.avl_left->field.avl_height > self->field.avl_height)) \
+ self->field.avl_height= self->field.avl_left->field.avl_height; \
+ if (self->field.avl_right && (self->field.avl_right->field.avl_height > self->field.avl_height)) \
+ self->field.avl_height= self->field.avl_right->field.avl_height; \
+ self->field.avl_height += 1; \
+ return self; \
+ } \
+ \
+ struct node *TREE_INSERT_##node##_##field \
+ (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
+ { \
+ if (!self) \
+ return elm; \
+ if (compare(elm, self) < 0) \
+ self->field.avl_left= TREE_INSERT_##node##_##field(self->field.avl_left, elm, compare); \
+ else \
+ self->field.avl_right= TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare); \
+ return TREE_BALANCE_##node##_##field(self); \
+ } \
+ \
+ struct node *TREE_FIND_##node##_##field \
+ (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
+ { \
+ if (!self) \
+ return 0; \
+ if (compare(elm, self) == 0) \
+ return self; \
+ if (compare(elm, self) < 0) \
+ return TREE_FIND_##node##_##field(self->field.avl_left, elm, compare); \
+ else \
+ return TREE_FIND_##node##_##field(self->field.avl_right, elm, compare); \
+ } \
+ \
+ int TREE_FIND_LESS_EQUAL_##node##_##field \
+ (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs), struct node **found, struct node **prev) \
+ { \
+ if (!self) \
+ return 0; \
+ if (compare(elm, self) == 0) { \
+ *found = self; \
+ return 1; \
+ } \
+ if (compare(elm, self) < 0) { \
+ int ret = TREE_FIND_LESS_EQUAL_##node##_##field(self->field.avl_left, elm, compare, found, prev); \
+ if (ret == 0 && *prev == NULL) { \
+ *prev = self; \
+ ret = -1; \
+ } \
+ return ret; \
+ } else { \
+ *found = self; \
+ *prev = self; \
+ return TREE_FIND_LESS_EQUAL_##node##_##field(self->field.avl_right, elm, compare, found, prev); \
+ } \
+ } \
+ \
+ struct node *TREE_MOVE_RIGHT_##node##_##field(struct node *self, struct node *rhs) \
+ { \
+ if (!self) \
+ return rhs; \
+ self->field.avl_right= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_right, rhs); \
+ return TREE_BALANCE_##node##_##field(self); \
+ } \
+ \
+ struct node *TREE_REMOVE_##node##_##field \
+ (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
+ { \
+ if (!self) return 0; \
+ \
+ if (compare(elm, self) == 0) \
+ { \
+ struct node *tmp= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_left, self->field.avl_right); \
+ self->field.avl_left= 0; \
+ self->field.avl_right= 0; \
+ return tmp; \
+ } \
+ if (compare(elm, self) < 0) \
+ self->field.avl_left= TREE_REMOVE_##node##_##field(self->field.avl_left, elm, compare); \
+ else \
+ self->field.avl_right= TREE_REMOVE_##node##_##field(self->field.avl_right, elm, compare); \
+ return TREE_BALANCE_##node##_##field(self); \
+ } \
+ \
+ void TREE_FORWARD_APPLY_ALL_##node##_##field \
+ (struct node *self, void (*function)(struct node *node, void *data), void *data) \
+ { \
+ if (self) \
+ { \
+ TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
+ function(self, data); \
+ TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
+ } \
+ } \
+ \
+ void TREE_REVERSE_APPLY_ALL_##node##_##field \
+ (struct node *self, void (*function)(struct node *node, void *data), void *data) \
+ { \
+ if (self) \
+ { \
+ TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
+ function(self, data); \
+ TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
+ } \
+ } \
+ \
+ void TREE_POST_ORDER_APPLY_ALL_##node##_##field \
+ (struct node *self, void (*function)(struct node *node, void *data), void *data) \
+ { \
+ if (self) \
+ { \
+ TREE_POST_ORDER_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
+ TREE_POST_ORDER_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
+ function(self, data); \
+ } \
+ } \
+ \
+ void TREE_REVERSE_APPLY_POST_ALL_##node##_##field \
+ (struct node *self, void (*function)(struct node *node, void *data), void *data) \
+ { \
+ if (self) \
+ { \
+ TREE_REVERSE_APPLY_POST_ALL_##node##_##field(self->field.avl_right, function, data); \
+ TREE_REVERSE_APPLY_POST_ALL_##node##_##field(self->field.avl_left, function, data); \
+ function(self, data); \
+ } \
+}
+
+#define TREE_INSERT(head, node, field, elm) \
+ ((head)->th_root= TREE_INSERT_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
+
+#define TREE_FIND(head, node, field, elm) \
+ (TREE_FIND_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
+
+#define TREE_FIND_LESS_EQUAL(head, node, field, elm, found, prev) \
+ (TREE_FIND_LESS_EQUAL_##node##_##field((head)->th_root, (elm), (head)->th_cmp, found, prev))
+
+#define TREE_REMOVE(head, node, field, elm) \
+ ((head)->th_root= TREE_REMOVE_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
+
+#define TREE_DEPTH(head, field) \
+ ((head)->th_root->field.avl_height)
+
+#define TREE_FORWARD_APPLY(head, node, field, function, data) \
+ TREE_FORWARD_APPLY_ALL_##node##_##field((head)->th_root, function, data)
+
+#define TREE_REVERSE_APPLY(head, node, field, function, data) \
+ TREE_REVERSE_APPLY_ALL_##node##_##field((head)->th_root, function, data)
+
+#define TREE_POST_ORDER_APPLY(head, node, field, function, data) \
+ TREE_POST_ORDER_APPLY_ALL_##node##_##field((head)->th_root, function, data)
+
+#define TREE_REVERSE_APPLY_POST(head, node, field, function, data) \
+ TREE_REVERSE_APPLY_POST_ALL_##node##_##field((head)->th_root, function, data)
+
+#define TREE_INIT(head, cmp) do { \
+ (head)->th_root= 0; \
+ (head)->th_cmp= (cmp); \
+ } while (0)
+
+
+#endif /* __tree_h */
diff --git a/src/config.h.in b/src/config.h.in
new file mode 100644
index 0000000..521adb8
--- /dev/null
+++ b/src/config.h.in
@@ -0,0 +1,307 @@
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Enable brief debugging messages. */
+#undef DEBUG_ENABLE_BRIEF
+
+/* Enable details debugging messages. */
+#undef DEBUG_ENABLE_DETAILS
+
+/* Enable verbose debugging messages. */
+#undef DEBUG_ENABLE_VERBOSE
+
+/* recvmmsg enabled */
+#undef ENABLE_RECVMMSG
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the <arpa/nameser.h> header file. */
+#undef HAVE_ARPA_NAMESER_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `epoll_wait' function. */
+#undef HAVE_EPOLL_WAIT
+
+/* Define to 1 if you have the <ev.h> header file. */
+#undef HAVE_EV_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `kqueue' function. */
+#undef HAVE_KQUEUE
+
+/* ldns present */
+#undef HAVE_LDNS
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Support mmx instructions */
+#undef HAVE_MMX
+
+/* Define to 1 if you have the `munmap' function. */
+#undef HAVE_MUNMAP
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define to 1 if you have the `regcomp' function. */
+#undef HAVE_REGCOMP
+
+/* Define to 1 if you have the <resolv.h> header file. */
+#undef HAVE_RESOLV_H
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the `sqrt' function. */
+#undef HAVE_SQRT
+
+/* Support SSE (Streaming SIMD Extensions) instructions */
+#undef HAVE_SSE
+
+/* Support SSE2 (Streaming SIMD Extensions 2) instructions */
+#undef HAVE_SSE2
+
+/* Support SSE3 (Streaming SIMD Extensions 3) instructions */
+#undef HAVE_SSE3
+
+/* Support SSSE3 (Supplemental Streaming SIMD Extensions 3) instructions */
+#undef HAVE_SSSE3
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the `strchr' function. */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <urcu.h> header file. */
+#undef HAVE_URCU_H
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define to 1 if the system has the type `_Bool'. */
+#undef HAVE__BOOL
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT64_T
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT8_T
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+#undef int64_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint16_t
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint32_t
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint64_t
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint8_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
diff --git a/src/knot/common.h b/src/knot/common.h
new file mode 100644
index 0000000..e9cfce1
--- /dev/null
+++ b/src/knot/common.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file common.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Common macros, includes and utilities.
+ *
+ * \addtogroup utils
+ * @{
+ */
+
+#ifndef _KNOTD_COMMON_H_
+#define _KNOTD_COMMON_H_
+
+#include <signal.h>
+#include <stdint.h>
+#include <config.h>
+
+/*
+ * Common types and constants.
+ */
+
+#ifndef UINT_DEFINED
+typedef unsigned int uint; /*!< \brief Unsigned. */
+#define UINT_DEFINED
+#endif
+
+#define PROJECT_EXEC SBINDIR "/" "knotd" /*!< \brief Project executable. */
+#define ZONEPARSER_EXEC LIBEXECDIR "/" "knot-zcompile" /*!< \brief Zoneparser executable. */
+#define PID_FILE "knot.pid" /*!< \brief Server PID file name. */
+
+/*
+ * Server.
+ */
+
+#define CPU_ESTIMATE_MAGIC 0 /*!< \brief Extra threads to the number of cores.*/
+#define DEFAULT_THR_COUNT 2 /*!< \brief Default thread count. */
+#define DEFAULT_PORT 53531 /*!< \brief Default interface port. */
+#define TCP_BACKLOG_SIZE 5 /*!< \brief TCP listen backlog size. */
+#define XFR_THREADS_COUNT 3 /*!< \brief Number of threads for XFR handler. */
+#define RECVMMSG_BATCHLEN 32 /*!< \brief Define for recvmmsg() batch size. */
+
+///*! \brief If defined, zone structures will use hash table for lookup. */
+//#define COMPRESSION_PEDANTIC
+
+///*!
+// * \brief If defined, tests will use ldns library to parse sample data.
+// *
+// * If not defined, some tests will be disabled.
+// */
+//#define TEST_WITH_LDNS
+
+///*! \brief If defined, the statistics module will be enabled. */
+//#define STAT_COMPILE
+
+
+#ifdef HAVE_LDNS
+#define TEST_WITH_LDNS
+#endif
+
+/*
+ * Common includes.
+ */
+
+#include "common/latency.h"
+#include "common/print.h"
+#include "knot/other/log.h"
+#include "knot/other/debug.h"
+
+/*! \brief Eliminate compiler warning with unused parameters. */
+#define UNUSED(param) (void)(param)
+
+/*! \brief Type-safe minimum macro. */
+#define MIN(a, b) \
+ ({ typeof (a) _a = (a); typeof (b) _b = (b); _a < _b ? _a : _b; })
+
+/*! \brief Type-safe maximum macro. */
+#define MAX(a, b) \
+ ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; })
+
+/* Optimisation macros. */
+#ifndef likely
+/*! \brief Optimize for x to be true value. */
+#define likely(x) __builtin_expect((x),1)
+#endif
+#ifndef unlikely
+/*! \brief Optimize for x to be false value. */
+#define unlikely(x) __builtin_expect((x),0)
+#endif
+
+/*! \todo Refactor theese. We should have an allocator function handling this.*/
+#ifndef ERR_ALLOC_FAILED
+#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d (%s)\n", \
+ __FILE__, __LINE__, PACKAGE_STRING)
+#endif
+
+#ifndef CHECK_ALLOC_LOG
+#define CHECK_ALLOC_LOG(var, ret) \
+ do { \
+ if ((var) == NULL) { \
+ ERR_ALLOC_FAILED; \
+ return (ret); \
+ } \
+ } while (0)
+#endif
+
+#ifndef CHECK_ALLOC
+#define CHECK_ALLOC(var, ret) \
+ do { \
+ if ((var) == NULL) { \
+ return (ret); \
+ } \
+ } while (0)
+#endif
+
+#endif /* _KNOTD_COMMON_H_ */
+
+/*! @} */
diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l
new file mode 100644
index 0000000..97ac8f8
--- /dev/null
+++ b/src/knot/conf/cf-lex.l
@@ -0,0 +1,218 @@
+/*!
+ * \file cf-lex.l
+ *
+ * \author Ondrej Sury <ondrej.sury@nic.cz>
+ *
+ * \brief Server configuration structures and API.
+ *
+ * IP address conversions from BIRD, (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ */
+%{
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "common/sockaddr.h"
+#include "knot/conf/conf.h"
+#include "knot/other/log.h"
+#include "libknotd_la-cf-parse.h" /* Automake generated header. */
+
+/* Imported symbols. */
+#define lval (yylval->tok)
+extern void cf_error(void *scanner, const char *msg);
+extern int (*cf_read_hook)(char *buf, size_t nbytes);
+void switch_input(const char *str, void *scanner)
+{
+ yy_scan_string(str, scanner);
+}
+
+//#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max);
+#define YY_NO_UNPUT
+
+%}
+
+%option reentrant
+%option bison-bridge
+%option noyywrap
+%option noinput
+%option nounput
+%option noreject
+%option yylineno
+%option prefix = "cf_"
+%option outfile = "lex.yy.c"
+
+ALPHA [a-zA-Z_]
+DIGIT [0-9]
+HEXA [0-9a-fA-F]
+ALNUM [a-zA-Z_0-9]
+BLANK [ \t\n]
+
+%%
+\#.*\n /* Ignore comments */;
+{BLANK}+ /* Ignore whitespace */;
+: /* Optional : in assignments. */;
+[\!\$\%\^\&\*\(\)\/\+\-\@\{\}\;\,] { return yytext[0]; }
+system { lval.t = yytext; return SYSTEM; }
+identity { lval.t = yytext; return IDENTITY; }
+version { lval.t = yytext; return VERSION; }
+storage { lval.t = yytext; return STORAGE; }
+key { lval.t = yytext; return KEY; }
+keys { lval.t = yytext; return KEYS; }
+remotes { lval.t = yytext; return REMOTES; }
+
+zones { lval.t = yytext; return ZONES; }
+file { lval.t = yytext; return FILENAME; }
+semantic-checks { lval.t = yytext; return SEMANTIC_CHECKS; }
+notify-retries { lval.t = yytext; return NOTIFY_RETRIES; }
+notify-timeout { lval.t = yytext; return NOTIFY_TIMEOUT; }
+zonefile-sync { lval.t = yytext; return DBSYNC_TIMEOUT; }
+ixfr-fslimit { lval.t = yytext; return IXFR_FSLIMIT; }
+xfr-in { lval.t = yytext; return XFR_IN; }
+xfr-out { lval.t = yytext; return XFR_OUT; }
+notify-in { lval.t = yytext; return NOTIFY_IN; }
+notify-out { lval.t = yytext; return NOTIFY_OUT; }
+workers { lval.t = yytext; return WORKERS; }
+
+interfaces { lval.t = yytext; return INTERFACES; }
+address { lval.t = yytext; return ADDRESS; }
+port { lval.t = yytext; return PORT; }
+
+log { lval.t = yytext; return LOG; }
+
+any { lval.t = yytext; lval.i = LOG_ANY; return LOG_SRC; }
+server { lval.t = yytext; lval.i = LOG_SERVER; return LOG_SRC; }
+answering { lval.t = yytext; lval.i = LOG_ANSWER; return LOG_SRC; }
+zone { lval.t = yytext; lval.i = LOG_ZONE; return LOG_SRC; }
+stdout { lval.t = yytext; lval.i = LOGT_STDOUT; return LOG_DEST; }
+stderr { lval.t = yytext; lval.i = LOGT_STDERR; return LOG_DEST; }
+syslog { lval.t = yytext; lval.i = LOGT_SYSLOG; return LOG_DEST; }
+all { lval.t = yytext; lval.i = LOG_UPTO(LOG_DEBUG); return LOG_LEVEL; }
+debug { lval.t = yytext; lval.i = LOG_MASK(LOG_DEBUG); return LOG_LEVEL; }
+info { lval.t = yytext; lval.i = LOG_MASK(LOG_INFO); return LOG_LEVEL; }
+notice { lval.t = yytext; lval.i = LOG_MASK(LOG_NOTICE); return LOG_LEVEL; }
+warning { lval.t = yytext; lval.i = LOG_MASK(LOG_WARNING); return LOG_LEVEL; }
+error { lval.t = yytext; lval.i = LOG_MASK(LOG_ERR); return LOG_LEVEL; }
+
+on|off {
+ lval.t = yytext;
+ lval.i = 0;
+ if (strcmp(yytext, "on") == 0) {
+ lval.i = 1;
+ }
+ return BOOL;
+}
+
+{DIGIT}+[smhd] {
+ size_t mpos = strlen(yytext) - 1;
+ char multiplier = yytext[mpos];
+ yytext[mpos] = '\0';
+ lval.i = atoi(yytext);
+ if (lval.i < 1) {
+ cf_error(yyscanner, "interval must be a positive integer");
+ return END;
+ }
+
+ /* Handle multiplier. */
+ switch(multiplier) {
+ case 'm': lval.i *= 60; break; /* minutes */
+ case 'h': lval.i *= 60*60; break; /* hours */
+ case 'd': lval.i *= 24*60*60; break; /* days */
+ case 's': /* seconds */
+ default: break;
+ }
+
+ return INTERVAL;
+}
+
+{DIGIT}+[kMG] {
+ size_t mpos = strlen(yytext) - 1;
+ char multiplier = yytext[mpos];
+ yytext[mpos] = '\0';
+ lval.i = atol(yytext);
+ if (lval.i < 1) {
+ cf_error(yyscanner, "size must be a positive integer");
+ return END;
+ }
+
+ /* Handle multiplier. */
+ switch(multiplier) {
+ case 'k': lval.l = lval.i * 1024; break; /* kB */
+ case 'M': lval.l = lval.i * 1024*1024; break; /* MB */
+ case 'G': lval.l = lval.i * 1024*1024*1024; break; /* GB */
+ default: break;
+ }
+
+ return SIZE;
+}
+
+{DIGIT}+ {
+ lval.i = atol(yytext);
+ return NUM;
+}
+
+{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
+ unsigned char buf[sizeof(struct in_addr)];
+ if (inet_pton(AF_INET, yytext, buf)) {
+ lval.t = strdup(yytext);
+ return IPA;
+ }
+ cf_error(yyscanner, "Invalid IP address.");
+}
+
+\[({HEXA}*::|({HEXA}*:){3,})({HEXA}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+)\] {
+#ifdef DISABLE_IPV6
+ lval.t = strdup(yytext);
+ cf_error(yyscanner, "IPv6 address support not compiled.");
+ return TEXT;
+#else
+ unsigned char buf[sizeof(struct in6_addr)];
+ yytext[strlen(yytext)-1] = '\0';
+ if (inet_pton(AF_INET6, yytext+1, buf)) {
+ lval.t = strdup(yytext+1);
+ return IPA6;
+ }
+ cf_error(yyscanner, "Invalid IPv6 address.");
+#endif
+ }
+
+({HEXA}*::|({HEXA}*:){3,})({HEXA}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
+#ifdef DISABLE_IPV6
+ lval.t = strdup(yytext);
+ cf_error(yyscanner, "IPv6 address support not compiled.");
+ return TEXT;
+#else
+ unsigned char buf[sizeof(struct in6_addr)];
+ if (inet_pton(AF_INET6, yytext, buf)) {
+ lval.t = strdup(yytext);
+ return IPA6;
+ }
+ cf_error(yyscanner, "Invalid IPv6 address.");
+#endif
+}
+
+gss-tsig { lval.alg = KNOT_TSIG_ALG_GSS_TSIG; return TSIG_ALGO_NAME; }
+hmac-md5 { lval.alg = KNOT_TSIG_ALG_HMAC_MD5; return TSIG_ALGO_NAME; }
+hmac-sha1 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA1; return TSIG_ALGO_NAME; }
+hmac-sha224 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA224; return TSIG_ALGO_NAME; }
+hmac-sha256 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA256; return TSIG_ALGO_NAME; }
+hmac-sha384 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA384; return TSIG_ALGO_NAME; }
+hmac-sha512 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA512; return TSIG_ALGO_NAME; }
+
+["][^"\n]*["] {
+ yytext[yyleng-1] = 0;
+ lval.t = strdup(yytext + 1);
+ return TEXT;
+}
+
+["][^"\n]*\n cf_error(yyscanner, "Unterminated string.");
+
+[a-zA-Z0-9\.\-\_]+ {
+ lval.t = strdup(yytext);
+ return TEXT /* Last resort, alphanumeric word. */;
+}
+
+<<EOF>> return END;
+
+%%
+
diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y
new file mode 100644
index 0000000..d793865
--- /dev/null
+++ b/src/knot/conf/cf-parse.y
@@ -0,0 +1,646 @@
+/*!
+ * \file cf-parse.y
+ *
+ * \author Ondrej Sury <ondrej.sury@nic.cz>
+ *
+ * \brief Server configuration structures and API.
+ */
+%{
+/* Headers */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libknot/dname.h"
+#include "knot/conf/conf.h"
+#include "libknotd_la-cf-parse.h" /* Automake generated header. */
+
+extern int cf_lex (YYSTYPE *lvalp, void *scanner);
+extern void cf_error(void *scanner, const char *msg);
+extern conf_t *new_config;
+static conf_iface_t *this_iface = 0;
+static conf_iface_t *this_remote = 0;
+static conf_zone_t *this_zone = 0;
+static list *this_list = 0;
+static conf_log_t *this_log = 0;
+static conf_log_map_t *this_logmap = 0;
+//#define YYERROR_VERBOSE 1
+
+static void conf_start_iface(char* ifname)
+{
+ this_iface = malloc(sizeof(conf_iface_t));
+ memset(this_iface, 0, sizeof(conf_iface_t));
+ this_iface->name = ifname;
+ this_iface->address = 0; // No default address (mandatory)
+ this_iface->port = CONFIG_DEFAULT_PORT;
+ add_tail(&new_config->ifaces, &this_iface->n);
+ ++new_config->ifaces_count;
+}
+
+static void conf_start_remote(char *remote)
+{
+ this_remote = malloc(sizeof(conf_iface_t));
+ memset(this_remote, 0, sizeof(conf_iface_t));
+ this_remote->name = remote;
+ this_remote->address = 0; // No default address (mandatory)
+ this_remote->port = 0; // Port wildcard
+ add_tail(&new_config->remotes, &this_remote->n);
+ ++new_config->remotes_count;
+}
+
+static void conf_acl_item(void *scanner, char *item)
+{
+ /* Find existing node in remotes. */
+ node* r = 0; conf_iface_t* found = 0;
+ WALK_LIST (r, new_config->remotes) {
+ if (strcmp(((conf_iface_t*)r)->name, item) == 0) {
+ found = (conf_iface_t*)r;
+ break;
+ }
+ }
+
+ /* Append to list if found. */
+ if (!found) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "remote '%s' is not defined", item);
+ cf_error(scanner, buf);
+ } else {
+ /* check port if xfrin/notify-out */
+ if (this_list == &this_zone->acl.xfr_in ||
+ this_list == &this_zone->acl.notify_out) {
+ if (found->port == 0) {
+ cf_error(scanner, "remote specified for XFR/IN or NOTIFY/OUT "
+ " needs to have valid port!");
+ free(item);
+ return;
+ }
+ }
+ conf_remote_t *remote = malloc(sizeof(conf_remote_t));
+ if (!remote) {
+ cf_error(scanner, "out of memory");
+ } else {
+ remote->remote = found;
+ add_tail(this_list, &remote->n);
+ }
+ }
+
+ /* Free text token. */
+ free(item);
+ }
+
+static int conf_key_exists(void *scanner, char *item)
+{
+ /* Find existing node in keys. */
+ knot_dname_t *sample = knot_dname_new_from_str(item, strlen(item), 0);
+ char buf[512];
+ conf_key_t* r = 0;
+ WALK_LIST (r, new_config->keys) {
+ if (knot_dname_compare(r->k.name, sample) == 0) {
+ snprintf(buf, sizeof(buf), "key '%s' is already defined", item);
+ cf_error(scanner, buf);
+ knot_dname_free(&sample);
+ return 1;
+ }
+ }
+
+ knot_dname_free(&sample);
+ return 0;
+}
+
+static int conf_key_add(void *scanner, knot_key_t **key, char *item)
+{
+ /* Reset */
+ *key = 0;
+
+ /* Find in keys */
+ knot_dname_t *sample = knot_dname_new_from_str(item, strlen(item), 0);
+
+ conf_key_t* r = 0;
+ WALK_LIST (r, new_config->keys) {
+ if (knot_dname_compare(r->k.name, sample) == 0) {
+ *key = &r->k;
+ knot_dname_free(&sample);
+ return 0;
+ }
+ }
+
+ char buf[512];
+ snprintf(buf, sizeof(buf), "key '%s' is not defined", item);
+ cf_error(scanner, buf);
+ knot_dname_free(&sample);
+ return 1;
+}
+
+%}
+
+%pure-parser
+%parse-param{void *scanner}
+%lex-param{void *scanner}
+%name-prefix = "cf_"
+
+%union {
+ struct {
+ char *t;
+ long i;
+ size_t l;
+ tsig_algorithm_t alg;
+ } tok;
+}
+
+%token END INVALID_TOKEN
+%token <tok> TEXT
+%token <tok> NUM
+%token <tok> INTERVAL
+%token <tok> SIZE
+%token <tok> BOOL
+
+%token <tok> SYSTEM IDENTITY VERSION STORAGE KEY KEYS
+%token <tok> TSIG_ALGO_NAME
+%token <tok> WORKERS
+
+%token <tok> REMOTES
+
+%token <tok> ZONES FILENAME
+%token <tok> SEMANTIC_CHECKS
+%token <tok> NOTIFY_RETRIES
+%token <tok> NOTIFY_TIMEOUT
+%token <tok> DBSYNC_TIMEOUT
+%token <tok> IXFR_FSLIMIT
+%token <tok> XFR_IN
+%token <tok> XFR_OUT
+%token <tok> NOTIFY_IN
+%token <tok> NOTIFY_OUT
+
+%token <tok> INTERFACES ADDRESS PORT
+%token <tok> IPA
+%token <tok> IPA6
+
+%token <tok> LOG
+%token <tok> LOG_DEST
+%token <tok> LOG_SRC
+%token <tok> LOG_LEVEL
+
+%%
+
+config: conf_entries END { return 0; } ;
+
+conf_entries:
+ /* EMPTY */
+ | conf_entries conf
+ ;
+
+interface_start:
+ | TEXT { conf_start_iface($1.t); }
+ | REMOTES { conf_start_iface(strdup($1.t)); } /* Allow strings reserved by token. */
+ | LOG_SRC { conf_start_iface(strdup($1.t)); }
+ | LOG { conf_start_iface(strdup($1.t)); }
+ | LOG_LEVEL { conf_start_iface(strdup($1.t)); }
+ ;
+
+interface:
+ interface_start '{'
+ | interface PORT NUM ';' {
+ if (this_iface->port != CONFIG_DEFAULT_PORT) {
+ cf_error(scanner, "only one port definition is allowed in interface section\n");
+ } else {
+ this_iface->port = $3.i;
+ }
+ }
+ | interface ADDRESS IPA ';' {
+ if (this_iface->address != 0) {
+ cf_error(scanner, "only one address is allowed in interface section\n");
+ } else {
+ this_iface->address = $3.t;
+ this_iface->family = AF_INET;
+ }
+ }
+ | interface ADDRESS IPA '@' NUM ';' {
+ if (this_iface->address != 0) {
+ cf_error(scanner, "only one address is allowed in interface section\n");
+ } else {
+ this_iface->address = $3.t;
+ this_iface->family = AF_INET;
+ if (this_iface->port != CONFIG_DEFAULT_PORT) {
+ cf_error(scanner, "only one port definition is allowed in interface section\n");
+ } else {
+ this_iface->port = $5.i;
+ }
+ }
+ }
+ | interface ADDRESS IPA6 ';' {
+ if (this_iface->address != 0) {
+ cf_error(scanner, "only one address is allowed in interface section\n");
+ } else {
+ this_iface->address = $3.t;
+ this_iface->family = AF_INET6;
+ }
+ }
+ | interface ADDRESS IPA6 '@' NUM ';' {
+ if (this_iface->address != 0) {
+ cf_error(scanner, "only one address is allowed in interface section\n");
+ } else {
+ this_iface->address = $3.t;
+ this_iface->family = AF_INET6;
+ if (this_iface->port != CONFIG_DEFAULT_PORT) {
+ cf_error(scanner, "only one port definition is allowed in interface section\n");
+ } else {
+ this_iface->port = $5.i;
+ }
+ }
+ }
+ ;
+
+interfaces:
+ INTERFACES '{'
+ | interfaces interface '}' {
+ if (this_iface->address == 0) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "interface '%s' has no defined address", this_iface->name);
+ cf_error(scanner, buf);
+ }
+ }
+ ;
+
+system:
+ SYSTEM '{'
+ | system VERSION TEXT ';' { new_config->version = $3.t; }
+ | system IDENTITY TEXT ';' { new_config->identity = $3.t; }
+ | system STORAGE TEXT ';' { new_config->storage = $3.t; }
+ | system KEY TSIG_ALGO_NAME TEXT ';' {
+ fprintf(stderr, "warning: Config option 'system.key' is deprecated "
+ "and has no effect.\n");
+ free($4.t);
+ }
+ | system WORKERS NUM ';' {
+ if ($3.i <= 0) {
+ cf_error(scanner, "worker count must be greater than 0\n");
+ } else {
+ new_config->workers = $3.i;
+ }
+ }
+ ;
+
+keys:
+ KEYS '{'
+ | keys TEXT TSIG_ALGO_NAME TEXT ';' {
+ /* Normalize to FQDN */
+ char *fqdn = $2.t;
+ if (fqdn[strlen(fqdn) - 1] != '.') {
+ char* tmp = malloc(strlen(fqdn) + 1 + 1); /* '.', '\0' */
+ if (!tmp) {
+ cf_error(scanner, "out of memory when allocating string");
+ free(fqdn);
+ fqdn = 0;
+ } else {
+ strcpy(tmp, fqdn);
+ strcat(tmp, ".");
+ free(fqdn);
+ fqdn = tmp;
+ }
+ }
+
+ if (!conf_key_exists(scanner, fqdn)) {
+ knot_dname_t *dname = knot_dname_new_from_str(fqdn, strlen(fqdn), 0);
+ if (!dname) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "key name '%s' not in valid domain "
+ "name format", fqdn);
+ cf_error(scanner, buf);
+ free(fqdn);
+ free($4.t);
+ } else {
+ conf_key_t *k = malloc(sizeof(conf_key_t));
+ memset(k, 0, sizeof(conf_key_t));
+ k->k.name = dname;
+ k->k.algorithm = $3.alg;
+ k->k.secret = $4.t;
+ add_tail(&new_config->keys, &k->n);
+ ++new_config->key_count;
+ free(fqdn);
+ }
+ } else {
+ free(fqdn);
+ free($4.t);
+ }
+}
+
+remote_start:
+ | TEXT { conf_start_remote($1.t); }
+ | LOG_SRC { conf_start_remote(strdup($1.t)); }
+ | LOG { conf_start_remote(strdup($1.t)); }
+ | LOG_LEVEL { conf_start_remote(strdup($1.t)); }
+ ;
+
+remote:
+ remote_start '{'
+ | remote PORT NUM ';' {
+ if (this_remote->port != 0) {
+ cf_error(scanner, "only one port definition is allowed in remote section\n");
+ } else {
+ this_remote->port = $3.i;
+ }
+ }
+ | remote ADDRESS IPA ';' {
+ if (this_remote->address != 0) {
+ cf_error(scanner, "only one address is allowed in remote section\n");
+ } else {
+ this_remote->address = $3.t;
+ this_remote->family = AF_INET;
+ }
+ }
+ | remote ADDRESS IPA '@' NUM ';' {
+ if (this_remote->address != 0) {
+ cf_error(scanner, "only one address is allowed in remote section\n");
+ } else {
+ this_remote->address = $3.t;
+ this_remote->family = AF_INET;
+ if (this_remote->port != 0) {
+ cf_error(scanner, "only one port definition is allowed in remote section\n");
+ } else {
+ this_remote->port = $5.i;
+ }
+ }
+ }
+ | remote ADDRESS IPA6 ';' {
+ if (this_remote->address != 0) {
+ cf_error(scanner, "only one address is allowed in remote section\n");
+ } else {
+ this_remote->address = $3.t;
+ this_remote->family = AF_INET6;
+ }
+ }
+ | remote ADDRESS IPA6 '@' NUM ';' {
+ if (this_remote->address != 0) {
+ cf_error(scanner, "only one address is allowed in remote section\n");
+ } else {
+ this_remote->address = $3.t;
+ this_remote->family = AF_INET6;
+ if (this_remote->port != 0) {
+ cf_error(scanner, "only one port definition is allowed in remote section\n");
+ } else {
+ this_remote->port = $5.i;
+ }
+ }
+ }
+ | remote KEY TEXT ';' {
+ if (this_remote->key != 0) {
+ cf_error(scanner, "only one TSIG key definition is allowed in remote section\n");
+ } else {
+ conf_key_add(scanner, &this_remote->key, $3.t);
+ }
+ }
+ ;
+
+remotes:
+ REMOTES '{'
+ | remotes remote '}' {
+ if (this_remote->address == 0) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "remote '%s' has no defined address", this_remote->name);
+ cf_error(scanner, buf);
+ }
+ }
+ ;
+
+zone_acl_start:
+ XFR_IN {
+ this_list = &this_zone->acl.xfr_in;
+ }
+ | XFR_OUT {
+ this_list = &this_zone->acl.xfr_out;
+ }
+ | NOTIFY_IN {
+ this_list = &this_zone->acl.notify_in;
+ }
+ | NOTIFY_OUT {
+ this_list = &this_zone->acl.notify_out;
+ }
+ ;
+
+zone_acl_item:
+ | TEXT { conf_acl_item(scanner, $1.t); }
+ | LOG_SRC { conf_acl_item(scanner, strdup($1.t)); }
+ | LOG { conf_acl_item(scanner, strdup($1.t)); }
+ | LOG_LEVEL { conf_acl_item(scanner, strdup($1.t)); }
+ ;
+
+zone_acl_list:
+ zone_acl_start
+ | zone_acl_list zone_acl_item ','
+ | zone_acl_list zone_acl_item ';'
+ ;
+
+zone_acl:
+ zone_acl_start '{'
+ | zone_acl TEXT ';' {
+ /* Find existing node in remotes. */
+ node* r = 0; conf_iface_t* found = 0;
+ WALK_LIST (r, new_config->remotes) {
+ if (strcmp(((conf_iface_t*)r)->name, $2.t) == 0) {
+ found = (conf_iface_t*)r;
+ break;
+ }
+ }
+
+ /* Append to list if found. */
+ if (!found) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "remote '%s' is not defined", $2.t);
+ cf_error(scanner, buf);
+ } else {
+ conf_remote_t *remote = malloc(sizeof(conf_remote_t));
+ if (!remote) {
+ cf_error(scanner, "out of memory");
+ } else {
+ remote->remote = found;
+ add_tail(this_list, &remote->n);
+ }
+ }
+
+ /* Free text token. */
+ free($2.t);
+ }
+ ;
+
+zone_start: TEXT {
+ this_zone = malloc(sizeof(conf_zone_t));
+ memset(this_zone, 0, sizeof(conf_zone_t));
+ this_zone->enable_checks = -1; // Default policy applies
+ this_zone->notify_timeout = -1; // Default policy applies
+ this_zone->notify_retries = 0; // Default policy applies
+ this_zone->ixfr_fslimit = -1; // Default policy applies
+ this_zone->dbsync_timeout = -1; // Default policy applies
+ this_zone->name = $1.t;
+
+ // Append mising dot to ensure FQDN
+ size_t nlen = strlen(this_zone->name);
+ if (this_zone->name[nlen - 1] != '.') {
+ this_zone->name = realloc(this_zone->name, nlen + 1 + 1);
+ strcat(this_zone->name, ".");
+ }
+
+ /* Check domain name. */
+ knot_dname_t *dn = knot_dname_new_from_str(this_zone->name,
+ nlen + 1,
+ 0);
+ if (dn == 0) {
+ free(this_zone->name);
+ free(this_zone);
+ cf_error(scanner, "invalid zone origin");
+ } else {
+ /* Directly discard dname, won't be needed. */
+ knot_dname_free(&dn);
+ add_tail(&new_config->zones, &this_zone->n);
+ ++new_config->zones_count;
+
+ /* Initialize ACL lists. */
+ init_list(&this_zone->acl.xfr_in);
+ init_list(&this_zone->acl.xfr_out);
+ init_list(&this_zone->acl.notify_in);
+ init_list(&this_zone->acl.notify_out);
+ }
+ }
+ ;
+
+zone:
+ zone_start '{'
+ | zone zone_acl '}'
+ | zone zone_acl_list
+ | zone FILENAME TEXT ';' { this_zone->file = $3.t; }
+ | zone SEMANTIC_CHECKS BOOL ';' { this_zone->enable_checks = $3.i; }
+ | zone DBSYNC_TIMEOUT NUM ';' { this_zone->dbsync_timeout = $3.i; }
+ | zone DBSYNC_TIMEOUT INTERVAL ';' { this_zone->dbsync_timeout = $3.i; }
+ | zone IXFR_FSLIMIT SIZE ';' { new_config->ixfr_fslimit = $3.l; }
+ | zone IXFR_FSLIMIT NUM ';' { this_zone->ixfr_fslimit = $3.i; }
+ | zone NOTIFY_RETRIES NUM ';' {
+ if ($3.i < 1) {
+ cf_error(scanner, "notify retries must be positive integer");
+ } else {
+ this_zone->notify_retries = $3.i;
+ }
+ }
+ | zone NOTIFY_TIMEOUT NUM ';' {
+ if ($3.i < 1) {
+ cf_error(scanner, "notify timeout must be positive integer");
+ } else {
+ this_zone->notify_timeout = $3.i;
+ }
+ }
+ ;
+
+zones:
+ ZONES '{'
+ | zones zone '}'
+ | zones SEMANTIC_CHECKS BOOL ';' { new_config->zone_checks = $3.i; }
+ | zones IXFR_FSLIMIT SIZE ';' { new_config->ixfr_fslimit = $3.l; }
+ | zones IXFR_FSLIMIT NUM ';' { new_config->ixfr_fslimit = $3.i; }
+ | zones NOTIFY_RETRIES NUM ';' {
+ if ($3.i < 1) {
+ cf_error(scanner, "notify retries must be positive integer");
+ } else {
+ new_config->notify_retries = $3.i;
+ }
+ }
+ | zones NOTIFY_TIMEOUT NUM ';' {
+ if ($3.i < 1) {
+ cf_error(scanner, "notify timeout must be positive integer");
+ } else {
+ new_config->notify_timeout = $3.i;
+ }
+ }
+ | zones DBSYNC_TIMEOUT NUM ';' {
+ if ($3.i < 1) {
+ cf_error(scanner, "zonefile sync timeout must be positive integer");
+ } else {
+ new_config->dbsync_timeout = $3.i;
+ }
+ }
+ | zones DBSYNC_TIMEOUT INTERVAL ';' { new_config->dbsync_timeout = $3.i; }
+ ;
+
+log_prios_start: {
+ this_logmap = malloc(sizeof(conf_log_map_t));
+ this_logmap->source = 0;
+ this_logmap->prios = 0;
+ add_tail(&this_log->map, &this_logmap->n);
+}
+;
+
+log_prios:
+ log_prios_start
+ | log_prios LOG_LEVEL ',' { this_logmap->prios |= $2.i; }
+ | log_prios LOG_LEVEL ';' { this_logmap->prios |= $2.i; }
+ ;
+
+log_src:
+ | log_src LOG_SRC log_prios {
+ this_logmap->source = $2.i;
+ this_logmap = 0;
+ }
+ ;
+
+log_dest: LOG_DEST {
+ /* Find already existing rule. */
+ this_log = 0;
+ node *n = 0;
+ WALK_LIST(n, new_config->logs) {
+ conf_log_t* log = (conf_log_t*)n;
+ if (log->type == $1.i) {
+ this_log = log;
+ break;
+ }
+ }
+
+ if (!this_log) {
+ this_log = malloc(sizeof(conf_log_t));
+ this_log->type = $1.i;
+ this_log->file = 0;
+ init_list(&this_log->map);
+ add_tail(&new_config->logs, &this_log->n);
+ ++new_config->logs_count;
+ }
+}
+;
+
+log_file: FILENAME TEXT {
+ /* Find already existing rule. */
+ this_log = 0;
+ node *n = 0;
+ WALK_LIST(n, new_config->logs) {
+ conf_log_t* log = (conf_log_t*)n;
+ if (log->type == LOGT_FILE) {
+ if (strcmp($2.t, log->file) == 0) {
+ this_log = log;
+ free($2.t);
+ break;
+ }
+ }
+ }
+
+ /* Create new rule. */
+ if (!this_log) {
+ this_log = malloc(sizeof(conf_log_t));
+ this_log->type = LOGT_FILE;
+ this_log->file = strcpath($2.t);
+ init_list(&this_log->map);
+ add_tail(&new_config->logs, &this_log->n);
+ ++new_config->logs_count;
+ }
+}
+;
+
+log_end: {
+}
+;
+
+log_start:
+ | log_start log_dest '{' log_src '}'
+ | log_start log_file '{' log_src '}'
+ ;
+
+log: LOG '{' log_start log_end;
+
+
+conf: ';' | system '}' | interfaces '}' | keys '}' | remotes '}' | zones '}' | log '}';
+
+%%
+
diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c
new file mode 100644
index 0000000..4e2d665
--- /dev/null
+++ b/src/knot/conf/conf.c
@@ -0,0 +1,715 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <urcu.h>
+#include "knot/conf/conf.h"
+#include "knot/common.h"
+#include "knot/other/error.h"
+
+/*
+ * Defaults.
+ */
+
+/*! \brief Default config paths. */
+static const char *DEFAULT_CONFIG[] = {
+ SYSCONFDIR "/" "knot.conf",
+};
+
+#define DEFAULT_CONF_COUNT 1 /*!< \brief Number of default config paths. */
+
+/*
+ * Utilities.
+ */
+
+/*!
+ * \brief Recursively create directories.
+ *
+ * Similar to "mkdir -p".
+ * * \retval 0 on success.
+ * \retval <0 on error.
+ */
+static int rmkdir(char *path, int mode)
+{
+ char *p = path;
+ while((p = strchr(p + 1, '/'))) {
+ *p = '\0';
+ mkdir(path, mode);
+ *p = '/';
+ }
+
+ // Final path
+ return mkdir(path, mode);
+}
+
+/* Prototypes for cf-parse.y */
+extern int cf_parse(void *scanner);
+extern int cf_get_lineno(void *scanner);
+extern char *cf_get_text(void *scanner);
+extern int cf_lex_init(void *scanner);
+extern void cf_set_in(FILE *f, void *scanner);
+extern void cf_lex_destroy(void *scanner);
+extern void switch_input(const char *str, void *scanner);
+
+conf_t *new_config = 0; /*!< \brief Currently parsed config. */
+static volatile int _parser_res = 0; /*!< \brief Parser result. */
+static pthread_mutex_t _parser_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*! \brief Config error report. */
+void cf_error(void *scanner, const char *msg)
+{
+ int lineno = -1;
+ char *text = "???";
+ if (scanner) {
+ lineno = cf_get_lineno(scanner);
+ text = (char *)cf_get_text(scanner);
+ }
+
+ log_server_error("Config '%s' - %s on line %d (current token '%s').\n",
+ new_config->filename, msg, lineno, text);
+
+
+ _parser_res = KNOTD_EPARSEFAIL;
+}
+
+/*
+ * Config helper functions.
+ */
+
+/*! \brief Free TSIG key. */
+static void key_free(conf_key_t *k)
+{
+ /* Secure erase. */
+ if (k->k.secret) {
+ memset(k->k.secret, 0, strlen(k->k.secret));
+ }
+ free(k->k.secret);
+ knot_dname_free(&k->k.name);
+ free(k);
+}
+
+/*! \brief Free config interfaces. */
+static void iface_free(conf_iface_t *iface)
+{
+ if (!iface) {
+ return;
+ }
+
+ free(iface->name);
+ free(iface->address);
+ free(iface);
+}
+
+/*! \brief Free config logs. */
+static void log_free(conf_log_t *log)
+{
+ if (!log) {
+ return;
+ }
+
+ if (log->file) {
+ free(log->file);
+ }
+
+ /* Free loglevel mapping. */
+ node *n = 0, *nxt = 0;
+ WALK_LIST_DELSAFE(n, nxt, log->map) {
+ free((conf_log_map_t*)n);
+ }
+
+ free(log);
+}
+
+/*! \brief Free config zones. */
+static void zone_free(conf_zone_t *zone)
+{
+ if (!zone) {
+ return;
+ }
+
+ /* Free ACL lists. */
+ WALK_LIST_FREE(zone->acl.xfr_in);
+ WALK_LIST_FREE(zone->acl.xfr_out);
+ WALK_LIST_FREE(zone->acl.notify_in);
+ WALK_LIST_FREE(zone->acl.notify_out);
+
+ free(zone->name);
+ free(zone->file);
+ free(zone->db);
+ free(zone->ixfr_db);
+ free(zone);
+}
+
+/*!
+ * \brief Call config hooks that need updating.
+ *
+ * This function is called automatically after config update.
+ *
+ * \todo Selective hooks.
+ */
+static void conf_update_hooks(conf_t *conf)
+{
+ node *n = 0;
+ conf->_touched = CONF_ALL;
+ WALK_LIST (n, conf->hooks) {
+ conf_hook_t *hook = (conf_hook_t*)n;
+ if ((hook->sections & conf->_touched) && hook->update) {
+ hook->update(conf, hook->data);
+ }
+ }
+}
+
+/*!
+ * \brief Process parsed configuration.
+ *
+ * This functions is called automatically after config parsing.
+ * It is needed to setup needed primitives, check and update paths.
+ *
+ * \retval 0 on success.
+ * \retval <0 on error.
+ */
+static int conf_process(conf_t *conf)
+{
+ // Check
+ if (!conf->storage) {
+ conf->storage = strdup("/var/lib/"PROJECT_EXEC);
+ }
+
+ // Normalize paths
+ conf->storage = strcpath(conf->storage);
+ struct stat st;
+ if (stat(conf->storage, &st) != 0) {
+ rmkdir(conf->storage, S_IRWXU);
+ }
+
+ // Create PID file
+ conf->pidfile = strcdup(conf->storage, "/" PID_FILE);
+
+ // Postprocess zones
+ node *n = 0;
+ WALK_LIST (n, conf->zones) {
+ conf_zone_t *zone = (conf_zone_t*)n;
+
+ // Default policy for dbsync timeout
+ if (zone->dbsync_timeout < 0) {
+ zone->dbsync_timeout = conf->dbsync_timeout;
+ }
+
+ // Default policy for semantic checks
+ if (zone->enable_checks < 0) {
+ zone->enable_checks = conf->zone_checks;
+ }
+
+ // Default policy for NOTIFY retries
+ if (zone->notify_retries <= 0) {
+ zone->notify_retries = conf->notify_retries;
+ }
+
+ // Default policy for NOTIFY timeout
+ if (zone->notify_timeout <= 0) {
+ zone->notify_timeout = conf->notify_timeout;
+ }
+
+ // Default policy for IXFR FSLIMIT
+ if (zone->ixfr_fslimit == 0) {
+ zone->ixfr_fslimit = conf->ixfr_fslimit;
+ }
+
+ // Normalize zone filename
+ zone->file = strcpath(zone->file);
+
+ // Create zone db filename
+ size_t stor_len = strlen(conf->storage);
+ size_t size = stor_len + strlen(zone->name) + 4; // db/,\0
+ char *dest = malloc(size);
+ strcpy(dest, conf->storage);
+ if (conf->storage[stor_len - 1] != '/') {
+ strcat(dest, "/");
+ }
+
+ strcat(dest, zone->name);
+ strcat(dest, "db");
+ zone->db = dest;
+
+ // Create IXFR db filename
+ stor_len = strlen(conf->storage);
+ size = stor_len + strlen(zone->name) + 9; // diff.db/,\0
+ dest = malloc(size);
+ strcpy(dest, conf->storage);
+ if (conf->storage[stor_len - 1] != '/') {
+ strcat(dest, "/");
+ }
+
+ strcat(dest, zone->name);
+ strcat(dest, "diff.db");
+ zone->ixfr_db = dest;
+ }
+
+ return 0;
+}
+
+/*
+ * Singletion configuration API.
+ */
+
+conf_t *s_config = 0; /*! \brief Singleton config instance. */
+
+/*! \brief Singleton config constructor (automatically called on load). */
+void __attribute__ ((constructor)) conf_init()
+{
+ // Create new config
+ s_config = conf_new(0);
+
+ /* Create default interface. */
+ conf_iface_t * iface = malloc(sizeof(conf_iface_t));
+ memset(iface, 0, sizeof(conf_iface_t));
+ iface->name = strdup("any");
+ iface->address = strdup("0.0.0.0");
+ iface->port = CONFIG_DEFAULT_PORT;
+ add_tail(&s_config->ifaces, &iface->n);
+ ++s_config->ifaces_count;
+
+ /* Create default storage. */
+ s_config->storage = strdup("/var/lib/"PROJECT_EXEC);
+
+ /* Create default logs. */
+
+ /* Syslog */
+ conf_log_t *log = malloc(sizeof(conf_log_t));
+ log->type = LOGT_SYSLOG;
+ log->file = 0;
+ init_list(&log->map);
+
+ conf_log_map_t *map = malloc(sizeof(conf_log_map_t));
+ map->source = LOG_ANY;
+ map->prios = LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR);
+ add_tail(&log->map, &map->n);
+ add_tail(&s_config->logs, &log->n);
+ ++s_config->logs_count;
+
+ /* Stderr */
+ log = malloc(sizeof(conf_log_t));
+ log->type = LOGT_STDERR;
+ log->file = 0;
+ init_list(&log->map);
+
+ map = malloc(sizeof(conf_log_map_t));
+ map->source = LOG_ANY;
+ map->prios = LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR);
+ add_tail(&log->map, &map->n);
+ add_tail(&s_config->logs, &log->n);
+ ++s_config->logs_count;
+
+ /* Process config. */
+ conf_process(s_config);
+}
+
+/*! \brief Singleton config destructor (automatically called on exit). */
+void __attribute__ ((destructor)) conf_deinit()
+{
+ if (s_config) {
+ conf_free(s_config);
+ s_config = 0;
+ }
+}
+
+/*!
+ * \brief Parse config (from file).
+ * \return yyparser return value.
+ */
+static int conf_fparser(conf_t *conf)
+{
+ if (!conf->filename) {
+ return KNOTD_EINVAL;
+ }
+
+ int ret = KNOTD_EOK;
+ pthread_mutex_lock(&_parser_lock);
+ // {
+ // Hook new configuration
+ new_config = conf;
+ FILE *f = fopen(conf->filename, "r");
+ if (f == 0) {
+ pthread_mutex_unlock(&_parser_lock);
+ return KNOTD_ENOENT;
+ }
+
+ // Parse config
+ _parser_res = KNOTD_EOK;
+ new_config->filename = conf->filename;
+ void *sc = NULL;
+ cf_lex_init(&sc);
+ cf_set_in(f, sc);
+ cf_parse(sc);
+ cf_lex_destroy(sc);
+ ret = _parser_res;
+ fclose(f);
+ // }
+ pthread_mutex_unlock(&_parser_lock);
+ return ret;
+}
+
+/*! \brief Parse config (from string).
+ * \return yyparser return value.
+ */
+static int conf_strparser(conf_t *conf, const char *src)
+{
+ if (!src) {
+ return KNOTD_EINVAL;
+ }
+
+ int ret = KNOTD_EOK;
+ pthread_mutex_lock(&_parser_lock);
+ // {
+ // Hook new configuration
+ new_config = conf;
+ if (src == 0) {
+ pthread_mutex_unlock(&_parser_lock);
+ return KNOTD_ENOENT;
+ }
+
+ // Parse config
+ _parser_res = KNOTD_EOK;
+ char *oldfn = new_config->filename;
+ new_config->filename = "(stdin)";
+ void *sc = NULL;
+ cf_lex_init(&sc);
+ switch_input(src, sc);
+ cf_parse(sc);
+ cf_lex_destroy(sc);
+ new_config->filename = oldfn;
+ ret = _parser_res;
+ // }
+ pthread_mutex_unlock(&_parser_lock);
+ return ret;
+}
+
+/*
+ * API functions.
+ */
+
+conf_t *conf_new(const char* path)
+{
+ conf_t *c = malloc(sizeof(conf_t));
+ memset(c, 0, sizeof(conf_t));
+
+ // Add path
+ if (path) {
+ c->filename = strdup(path);
+ }
+
+ // Initialize lists
+ init_list(&c->logs);
+ init_list(&c->ifaces);
+ init_list(&c->zones);
+ init_list(&c->hooks);
+ init_list(&c->remotes);
+ init_list(&c->keys);
+
+ // Defaults
+ c->zone_checks = 0;
+ c->notify_retries = CONFIG_NOTIFY_RETRIES;
+ c->notify_timeout = CONFIG_NOTIFY_TIMEOUT;
+ c->dbsync_timeout = CONFIG_DBSYNC_TIMEOUT;
+ c->ixfr_fslimit = -1;
+
+ return c;
+}
+
+int conf_add_hook(conf_t * conf, int sections,
+ int (*on_update)(const conf_t*, void*), void *data)
+{
+ conf_hook_t *hook = malloc(sizeof(conf_hook_t));
+ if (!hook) {
+ return KNOTD_ENOMEM;
+ }
+
+ hook->sections = sections;
+ hook->update = on_update;
+ hook->data = data;
+ add_tail(&conf->hooks, &hook->n);
+ ++conf->hooks_count;
+
+ return KNOTD_EOK;
+}
+
+int conf_parse(conf_t *conf)
+{
+ /* Parse file. */
+ int ret = conf_fparser(conf);
+
+ /* Postprocess config. */
+ conf_process(conf);
+
+ /* Update hooks. */
+ conf_update_hooks(conf);
+
+ if (ret < 0) {
+ return KNOTD_EPARSEFAIL;
+ }
+
+ return KNOTD_EOK;
+}
+
+int conf_parse_str(conf_t *conf, const char* src)
+{
+ /* Parse config from string. */
+ int ret = conf_strparser(conf, src);
+
+ /* Postprocess config. */
+ conf_process(conf);
+
+ /* Update hooks */
+ conf_update_hooks(conf);
+
+ if (ret < 0) {
+ return KNOTD_EPARSEFAIL;
+ }
+
+ return KNOTD_EOK;
+}
+
+void conf_truncate(conf_t *conf, int unload_hooks)
+{
+ if (!conf) {
+ return;
+ }
+
+ node *n = 0, *nxt = 0;
+
+ // Unload hooks
+ if (unload_hooks) {
+ WALK_LIST_DELSAFE(n, nxt, conf->hooks) {
+ //! \todo call hook unload.
+ free((conf_hook_t*)n);
+ }
+ conf->hooks_count = 0;
+ init_list(&conf->hooks);
+ }
+
+ // Free keys
+ WALK_LIST_DELSAFE(n, nxt, conf->keys) {
+ key_free((conf_key_t *)n);
+ }
+
+ // Free interfaces
+ WALK_LIST_DELSAFE(n, nxt, conf->ifaces) {
+ iface_free((conf_iface_t*)n);
+ }
+ conf->ifaces_count = 0;
+ init_list(&conf->ifaces);
+
+ // Free logs
+ WALK_LIST_DELSAFE(n, nxt, conf->logs) {
+ log_free((conf_log_t*)n);
+ }
+ conf->logs_count = 0;
+ init_list(&conf->logs);
+
+ // Free remotes
+ WALK_LIST_DELSAFE(n, nxt, conf->remotes) {
+ iface_free((conf_iface_t*)n);
+ }
+ conf->remotes_count = 0;
+ init_list(&conf->remotes);
+
+ // Free zones
+ WALK_LIST_DELSAFE(n, nxt, conf->zones) {
+ zone_free((conf_zone_t*)n);
+ }
+ conf->zones_count = 0;
+ init_list(&conf->zones);
+
+ if (conf->filename) {
+ free(conf->filename);
+ conf->filename = 0;
+ }
+ if (conf->identity) {
+ free(conf->identity);
+ conf->identity = 0;
+ }
+ if (conf->version) {
+ free(conf->version);
+ conf->version = 0;
+ }
+ if (conf->storage) {
+ free(conf->storage);
+ conf->storage = 0;
+ }
+ if (conf->pidfile) {
+ free(conf->pidfile);
+ conf->pidfile = 0;
+ }
+}
+
+void conf_free(conf_t *conf)
+{
+ if (!conf) {
+ return;
+ }
+
+ // Truncate config
+ conf_truncate(conf, 1);
+
+ // Free config
+ free(conf);
+}
+
+char* conf_find_default()
+{
+ /* Try sequentially each default path. */
+ char *path = 0;
+ for (int i = 0; i < DEFAULT_CONF_COUNT; ++i) {
+ path = strcpath(strdup(DEFAULT_CONFIG[i]));
+
+ /* Break, if the path exists. */
+ struct stat st;
+ if (stat(path, &st) == 0) {
+ break;
+ }
+
+ log_server_notice("Config '%s' does not exist.\n",
+ path);
+
+ /* Keep the last item. */
+ if (i < DEFAULT_CONF_COUNT - 1) {
+ free(path);
+ path = 0;
+ }
+ }
+
+ log_server_info("Using '%s' as default configuration.\n",
+ path);
+ return path;
+}
+
+int conf_open(const char* path)
+{
+ /* Check path. */
+ if (!path) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Check if exists. */
+ FILE *fp = fopen(path, "r");
+ if (fp == 0) {
+ return KNOTD_ENOENT;
+ } else {
+ fclose(fp);
+ }
+
+ /* Create new config. */
+ conf_t *nconf = conf_new(path);
+
+ /* Parse config. */
+ int ret = conf_fparser(nconf);
+ if (ret != KNOTD_EOK) {
+ conf_free(nconf);
+ return ret;
+ }
+
+ /* Replace current config. */
+ conf_t *oldconf = rcu_xchg_pointer(&s_config, nconf);
+
+ /* Copy hooks. */
+ if (oldconf) {
+ node *n = 0, *nxt = 0;
+ WALK_LIST_DELSAFE (n, nxt, oldconf->hooks) {
+ conf_hook_t *hook = (conf_hook_t*)n;
+ conf_add_hook(nconf, hook->sections,
+ hook->update, hook->data);
+ }
+ }
+
+ /* Postprocess config. */
+ conf_process(nconf);
+
+ /* Synchronize. */
+ synchronize_rcu();
+
+ /* Free old config. */
+ if (oldconf) {
+ conf_free(oldconf);
+ }
+
+ /* Update hooks. */
+ conf_update_hooks(nconf);
+
+ return KNOTD_EOK;
+}
+
+char* strcdup(const char *s1, const char *s2)
+{
+ if (!s1 || !s2) {
+ return 0;
+ }
+
+ size_t slen = strlen(s1);
+ size_t nlen = slen + strlen(s2) + 1;
+ char* dst = malloc(nlen);
+ if (!dst) {
+ return 0;
+ }
+
+ memcpy(dst, s1, slen);
+ strcpy(dst + slen, s2); // With trailing '\0'
+ return dst;
+}
+
+char* strcpath(char *path)
+{
+ // NULL path
+ if (!path) {
+ return 0;
+ }
+
+ // Remote trailing slash
+ size_t plen = strlen(path);
+ if (path[plen - 1] == '/') {
+ path[--plen] = '\0';
+ }
+
+ // Expand '~'
+ char* tild_p = strchr(path,'~');
+ if (tild_p != 0) {
+ // Get full path
+ char *tild_exp = getenv("HOME");
+ size_t tild_len = strlen(tild_exp);
+ if (tild_exp[tild_len - 1] == '/') {
+ tild_exp[--tild_len] = '\0';
+ }
+
+ // Expand
+ char *npath = malloc(plen + tild_len + 1);
+ npath[0] = '\0';
+ strncpy(npath, path, (size_t)(tild_p - path));
+ strcat(npath, tild_exp);
+ strcat(npath, tild_p + 1);
+ free(path);
+ path = npath;
+ }
+
+ return path;
+}
+
diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h
new file mode 100644
index 0000000..ef35e41
--- /dev/null
+++ b/src/knot/conf/conf.h
@@ -0,0 +1,361 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file conf.h
+ *
+ * \author Ondrej Sury <ondrej.sury@nic.cz>
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Server configuration structures and API.
+ *
+ * \addtogroup config
+ * @{
+ */
+
+#ifndef _KNOTD_CONF_H_
+#define _KNOTD_CONF_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <urcu.h>
+
+#include "libknot/dname.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/tsig.h"
+#include "common/lists.h"
+#include "knot/other/log.h"
+
+/* Constants. */
+#define CONFIG_DEFAULT_PORT 53
+#define CONFIG_NOTIFY_RETRIES 5 /*!< 5 retries (suggested in RFC1996) */
+#define CONFIG_NOTIFY_TIMEOUT 60 /*!< 60s (suggested in RFC1996) */
+#define CONFIG_DBSYNC_TIMEOUT (60*60) /*!< 1 hour. */
+
+/*!
+ * \brief Configuration for the interface
+ *
+ * This structure holds the configuration of the various interfaces
+ * used in the configuration. Same interface could be used for
+ * listening and outgoing function.
+ */
+typedef struct conf_iface_t {
+ node n;
+ char *name; /*!< Internal name for the interface. */
+ char *address; /*!< IP (IPv4/v6) address for this interface */
+ int port; /*!< Port number for this interface */
+ int family; /*!< Address family. */
+ knot_key_t *key; /*!< TSIG key (only valid for remotes). */
+} conf_iface_t;
+
+/*!
+ * \brief Node containing poiner to remote.
+ *
+ * Used for zone ACL lists to prevent node duplication.
+ */
+typedef struct conf_remote_t {
+ node n; /*!< List node. */
+ conf_iface_t *remote; /*!< Pointer to interface descriptor. */
+} conf_remote_t;
+
+/*!
+ * \brief Zone configuration.
+ *
+ * This structure holds the configuration for the zone. In it's most
+ * basic form, it just allows to read a zone from the specific
+ * location on the disk. It also allows to have multiple DNS servers
+ * as a source for the zone transfer and multiple DNS servers to allow
+ * zone transfers. Same logic applies for the NOTIFY.
+ *
+ * \todo Missing XFR type (AXFR/IXFR/IXFR-ONLY) for each server.
+ */
+typedef struct conf_zone_t {
+ node n;
+ char *name; /*!< Zone name. */
+ enum knot_rr_class cls; /*!< Zone class (IN or CH). */
+ char *file; /*!< Path to a zone file. */
+ char *db; /*!< Path to a database file. */
+ char *ixfr_db; /*!< Path to a IXFR database file. */
+ size_t ixfr_fslimit; /*!< File size limit for IXFR journal. */
+ int dbsync_timeout; /*!< Interval between syncing to zonefile.*/
+ int enable_checks; /*!< Semantic checks for parser.*/
+ int notify_retries; /*!< NOTIFY query retries. */
+ int notify_timeout; /*!< Timeout for NOTIFY response (s). */
+ struct {
+ list xfr_in; /*!< Remotes accepted for for xfr-in.*/
+ list xfr_out; /*!< Remotes accepted for xfr-out.*/
+ list notify_in; /*!< Remotes accepted for notify-in.*/
+ list notify_out; /*!< Remotes accepted for notify-out.*/
+ } acl;
+} conf_zone_t;
+
+/*!
+ * \brief Mapping of loglevels to message sources.
+ */
+typedef struct conf_log_map_t {
+ node n;
+ int source; /*!< Log message source mask. */
+ int prios; /*!< Log priorities mask. */
+} conf_log_map_t;
+
+/*!
+ * \brief Log facility descriptor.
+ */
+typedef struct conf_log_t {
+ node n;
+ logtype_t type; /*!< Type of the log (SYSLOG/STDERR/FILE). */
+ char *file; /*!< Filename in case of LOG_FILE, else NULL. */
+ list map; /*!< Log levels mapping. */
+} conf_log_t;
+
+/*!
+ * \brief Configuration sections.
+ */
+typedef enum conf_section_t {
+ CONF_LOG = 1 << 0, /*!< Log section. */
+ CONF_IFACES = 1 << 1, /*!< Interfaces. */
+ CONF_ZONES = 1 << 2, /*!< Zones. */
+ CONF_OTHER = 1 << 3, /*!< Other sections. */
+ CONF_ALL = ~0 /*!< All sections. */
+} conf_section_t;
+
+/*!
+ * \brief TSIG key list item.
+ */
+typedef struct conf_key_t {
+ node n;
+ knot_key_t k;
+} conf_key_t;
+
+/*!
+ * \brief Main config structure.
+ *
+ * Configuration structure.
+ */
+typedef struct conf_t {
+ /*
+ * System
+ */
+ char *filename; /*!< Name of the config file. */
+ char *identity; /*!< Identity to return on CH TXT id.server. */
+ char *version; /*!< Version for CH TXT version.{bind|server} */
+ char *storage; /*!< Persistent storage path for databases and such. */
+ char *pidfile; /*!< PID file path. */
+ int workers; /*!< Number of workers per interface. */
+
+ /*
+ * Log
+ */
+ list logs; /*!< List of logging facilites. */
+ int logs_count; /*!< Count of logging facilities. */
+
+ /*
+ * Interfaces
+ */
+ list ifaces; /*!< List of interfaces. */
+ int ifaces_count; /*!< Count of interfaces. */
+
+ /*
+ * TSIG keys
+ */
+ list keys; /*!< List of TSIG keys. */
+ int key_count; /*!< Count of TSIG keys. */
+
+ /*
+ * Remotes
+ */
+ list remotes; /*!< List of remotes. */
+ int remotes_count;/*!< Count of remotes. */
+
+ /*
+ * Zones
+ */
+ list zones; /*!< List of zones. */
+ int zones_count; /*!< Count of zones. */
+ int zone_checks; /*!< Semantic checks for parser.*/
+ int notify_retries; /*!< NOTIFY query retries. */
+ int notify_timeout; /*!< Timeout for NOTIFY response in seconds. */
+ int dbsync_timeout; /*!< Default interval between syncing to zonefile.*/
+ size_t ixfr_fslimit; /*!< File size limit for IXFR journal. */
+
+ /*
+ * Implementation specifics
+ */
+ list hooks; /*!< List of config hooks. */
+ int hooks_count; /*!< Count of config hooks. */
+ int _touched; /*!< Bitmask of sections touched by last update. */
+} conf_t;
+
+/*!
+ * \brief Config hook prototype.
+ */
+typedef struct conf_hook_t {
+ node n;
+ int sections; /*!< Bitmask of watched sections. */
+ int (*update)(const conf_t*, void*); /*!< Function executed on config load. */
+ void *data;
+} conf_hook_t;
+
+/*
+ * Specific configuration API.
+ */
+
+/*!
+ * \brief Create new configuration structure.
+ *
+ * \param path Path to configuration file.
+ * \retval new structure if successful.
+ * \retval NULL on error.
+ */
+conf_t *conf_new(const char* path);
+
+/*!
+ * \brief Register on-update callback.
+ *
+ * \param conf Configuration context.
+ * \param sections Bitmask of watched sections or CONF_ALL.
+ * \param on_update Callback.
+ * \param data User specified data for hook.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_ENOMEM out of memory error.
+ */
+int conf_add_hook(conf_t * conf, int sections,
+ int (*on_update)(const conf_t*, void*), void *data);
+
+/*!
+ * \brief Parse configuration from associated file.
+ *
+ * \note Registered callbacks may be executed if applicable.
+ *
+ * \param conf Configuration context.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EPARSEFAIL on parser error.
+ */
+int conf_parse(conf_t *conf);
+
+/*!
+ * \brief Parse configuration from string.
+ *
+ * \note Registered callbacks may be executed if applicable.
+ *
+ * \param conf Configuration context.
+ * \param src Source string.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EPARSEFAIL on parser error.
+ */
+int conf_parse_str(conf_t *conf, const char* src);
+
+/*!
+ * \brief Truncate configuration context.
+ *
+ * \param conf Configuration context.
+ * \param unload_hooks If true, hooks will be unregistered and freed as well.
+ */
+void conf_truncate(conf_t *conf, int unload_hooks);
+
+/*!
+ * \brief Destroy configuration context.
+ *
+ * \param conf Configuration context.
+ */
+void conf_free(conf_t *conf);
+
+/*
+ * Singleton configuration API.
+ */
+
+/*!
+ * \brief Find implicit configuration file.
+ *
+ * Ordering:
+ * 1. ~/.knot/knot.conf (if exists)
+ * 2. /etc/knot/knot.conf (fallback)
+ *
+ * \return Path to implicit configuration file.
+ */
+char* conf_find_default();
+
+/*!
+ * \brief Open singleton configuration from file.
+ *
+ * \note Registered callbacks may be executed if applicable.
+ *
+ * \param path Path to configuration file.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on null path.
+ * \retval KNOTD_ENOENT if the path doesn't exist.
+ */
+int conf_open(const char* path);
+
+/* Imported singleton */
+extern conf_t *s_config;
+
+/*!
+ * \brief Singleton configuration context accessor.
+ *
+ * \return Configuration context.
+ */
+static inline conf_t* conf() {
+ return s_config; // Inline for performance reasons.
+}
+
+/*!
+ * \brief Lock configuration for reading.
+ *
+ * \return Configuration context.
+ */
+static inline void conf_read_lock() {
+ rcu_read_lock();
+}
+
+/*!
+ * \brief Unlock configuration for reading.
+ */
+static inline void conf_read_unlock() {
+ rcu_read_unlock();
+}
+
+/*
+ * Utilities.
+ */
+
+/*!
+ * \brief Create new string from a concatenation of s1 and s2.
+ *
+ * \param s1 First string.
+ * \param s2 Second string.
+ *
+ * \retval Newly allocated string on success.
+ * \retval NULL on error.
+ */
+char* strcdup(const char *s1, const char *s2);
+
+/*!
+ * \brief Normalize file path and expand '~' placeholders.
+ *
+ * \note Old pointer may be freed.
+ *
+ * \retval Pointer to normalized path.
+ */
+char* strcpath(char *path);
+
+#endif /* _KNOTD_CONF_H_ */
+
+/*! @} */
diff --git a/src/knot/conf/logconf.c b/src/knot/conf/logconf.c
new file mode 100644
index 0000000..a57afd9
--- /dev/null
+++ b/src/knot/conf/logconf.c
@@ -0,0 +1,102 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "knot/other/debug.h"
+#include "knot/conf/logconf.h"
+#include "knot/conf/conf.h"
+#include "knot/other/log.h"
+#include "knot/other/error.h"
+#include "common/lists.h"
+#include "knot/common.h"
+
+int log_conf_hook(const struct conf_t *conf, void *data)
+{
+ // Data not used
+ int ret = 0;
+ UNUSED(data);
+
+ // Check if log declaration exists, otherwise ignore
+ if (conf->logs_count < 1) {
+ return KNOTD_EINVAL;
+ }
+
+ // Find maximum log facility id
+ node *n = 0; size_t files = 0;
+ WALK_LIST(n, conf->logs) {
+ conf_log_t* log = (conf_log_t*)n;
+ if (log->type == LOGT_FILE) {
+ ++files;
+ }
+ }
+
+ // Initialize logsystem
+ log_truncate();
+ if ((ret = log_setup(files)) < 0) {
+ return ret;
+ }
+
+ // Setup logs
+ int loaded_sections = 0;
+ n = 0;
+ WALK_LIST(n, conf->logs) {
+
+ // Calculate offset
+ conf_log_t* log = (conf_log_t*)n;
+ int facility = log->type;
+ if (facility == LOGT_FILE) {
+ facility = log_open_file(log->file);
+ if (facility < 0) {
+ log_server_error("Failed to open "
+ "logfile '%s'.\n", log->file);
+ continue;
+ }
+ }
+
+ // Auto-assign fatal errors to syslog or stderr
+ if (facility <= LOGT_STDERR) {
+ int mask = LOG_MASK(LOG_FATAL);
+ log_levels_add(facility, LOG_ANY, mask);
+ loaded_sections |= 1 << facility;
+ }
+
+ // Setup sources mapping
+ node *m = 0;
+ WALK_LIST(m, log->map) {
+
+ // Assign mapped level
+ conf_log_map_t *map = (conf_log_map_t*)m;
+ log_levels_add(facility, map->source, map->prios);
+ }
+ }
+
+ // Load defaults for syslog or stderr
+ int bmask = LOG_MASK(LOG_ERR)|LOG_MASK(LOG_FATAL);
+ if (!(loaded_sections & (1 << LOGT_SYSLOG))) {
+ log_levels_set(LOGT_SYSLOG, LOG_ANY, bmask);
+ }
+ if (!(loaded_sections & (1 << LOGT_STDERR))) {
+ log_levels_set(LOGT_STDERR, LOG_ANY, bmask);
+ }
+
+ return KNOTD_EOK;
+}
+
diff --git a/src/knot/conf/logconf.h b/src/knot/conf/logconf.h
new file mode 100644
index 0000000..7b9e054
--- /dev/null
+++ b/src/knot/conf/logconf.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file log.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Logging facility (configuration file interface).
+ *
+ * \addtogroup logging
+ * @{
+ */
+
+#ifndef _KNOTD_LOGCONF_H_
+#define _KNOTD_LOGCONF_H_
+
+struct conf_t;
+
+/*!
+ * \brief Setup logging facilities from config.
+ *
+ * \see syslog.h
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ENOMEM out of memory error.
+ */
+int log_conf_hook(const struct conf_t *conf, void *data);
+
+#endif /* _KNOTD_LOGCONF_H_ */
+
+/*! @} */
diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c
new file mode 100644
index 0000000..16c3863
--- /dev/null
+++ b/src/knot/ctl/knotc_main.c
@@ -0,0 +1,658 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <getopt.h>
+
+#include "knot/common.h"
+#include "knot/other/error.h"
+#include "knot/ctl/process.h"
+#include "knot/conf/conf.h"
+#include "knot/conf/logconf.h"
+#include "knot/zone/zone-load.h"
+
+/*! \brief Controller constants. */
+enum knotc_constants_t {
+ WAITPID_TIMEOUT = 10 /*!< \brief Timeout for waiting for process. */
+};
+
+/*! \brief Print help. */
+void help(int argc, char **argv)
+{
+ printf("Usage: %sc [parameters] start|stop|restart|reload|running|"
+ "compile\n", PACKAGE_NAME);
+ printf("Parameters:\n"
+ " -c [file], --config=[file] Select configuration file.\n"
+ " -j [num], --jobs=[num] Number of parallel tasks to run (only for 'compile').\n"
+ " -f, --force Force operation - override some checks.\n"
+ " -v, --verbose Verbose mode - additional runtime information.\n"
+ " -V, --version Print %s server version.\n"
+ " -w, --wait Wait for the server to finish start/stop operations.\n"
+ " -i, --interactive Interactive mode (do not daemonize).\n"
+ " -h, --help Print help and usage.\n",
+ PACKAGE_NAME);
+ printf("Actions:\n"
+ " start Start %s server zone (no-op if running).\n"
+ " stop Stop %s server (no-op if not running).\n"
+ " restart Stops and then starts %s server.\n"
+ " reload Reload %s configuration and compiled zones.\n"
+ " running check if server is running.\n"
+ "\n"
+ " compile Compile zone file.\n",
+ PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME);
+}
+
+/*!
+ * \brief Check if the zone needs recompilation.
+ *
+ * \param db Path to zone db file.
+ * \param source Path to zone source file.
+ *
+ * \retval KNOTD_EOK if up to date.
+ * \retval KNOTD_ERROR if needs recompilation.
+ */
+int check_zone(const char *db, const char* source)
+{
+ /* Check zonefile. */
+ struct stat st;
+ if (stat(source, &st) != 0) {
+ fprintf(stderr, "Zone file '%s' doesn't exist.\n", source);
+ return KNOTD_ENOENT;
+ }
+
+ /* Read zonedb header. */
+ zloader_t *zl = 0;
+ knot_zload_open(&zl, db);
+ if (!zl) {
+ return KNOTD_ERROR;
+ }
+
+ /* Check source files and mtime. */
+ int ret = KNOTD_ERROR;
+ int src_changed = strcmp(source, zl->source) != 0;
+ if (!src_changed && !knot_zload_needs_update(zl)) {
+ ret = KNOTD_EOK;
+ }
+
+ knot_zload_close(zl);
+ return ret;
+}
+
+pid_t wait_cmd(pid_t proc, int *rc)
+{
+ /* Wait for finish. */
+ sigset_t newset;
+ sigfillset(&newset);
+ sigprocmask(SIG_BLOCK, &newset, 0);
+ proc = waitpid(proc, rc, 0);
+ sigprocmask(SIG_UNBLOCK, &newset, 0);
+ return proc;
+}
+
+pid_t start_cmd(const char *argv[], int argc)
+{
+ pid_t chproc = fork();
+ if (chproc == 0) {
+
+ /* Duplicate, it doesn't run from stack address anyway. */
+ char **args = malloc((argc + 1) * sizeof(char*));
+ memset(args, 0, (argc + 1) * sizeof(char*));
+ int ci = 0;
+ for (int i = 0; i < argc; ++i) {
+ if (strlen(argv[i]) > 0) {
+ args[ci++] = strdup(argv[i]);
+ }
+ }
+ args[ci] = 0;
+
+ /* Execute command. */
+ fflush(stdout);
+ fflush(stderr);
+ execvp(args[0], args);
+
+ /* Execute failed. */
+ fprintf(stderr, "Failed to run executable '%s'\n", args[0]);
+ for (int i = 0; i < argc; ++i) {
+ free(args[i]);
+ }
+ free(args);
+
+ exit(1);
+ return -1;
+ }
+
+ return chproc;
+}
+
+int exec_cmd(const char *argv[], int argc)
+{
+ int ret = 0;
+ pid_t proc = start_cmd(argv, argc);
+ wait_cmd(proc, &ret);
+ return ret;
+}
+
+/*! \brief Zone compiler task. */
+typedef struct {
+ conf_zone_t *zone;
+ pid_t proc;
+} knotc_zctask_t;
+
+/*! \brief Create set of watched tasks. */
+knotc_zctask_t *zctask_create(int count)
+{
+ if (count <= 0) {
+ return 0;
+ }
+
+ knotc_zctask_t *t = malloc(count * sizeof(knotc_zctask_t));
+ for (unsigned i = 0; i < count; ++i) {
+ t[i].proc = -1;
+ t[i].zone = 0;
+ }
+
+ return t;
+}
+
+/*! \brief Wait for single task to finish. */
+int zctask_wait(knotc_zctask_t *tasks, int count)
+{
+ /* Wait for children to finish. */
+ int rc = 0;
+ pid_t pid = wait_cmd(-1, &rc);
+
+ /* Find task. */
+ conf_zone_t *z = 0;
+ for (unsigned i = 0; i < count; ++i) {
+ if (tasks[i].proc == pid) {
+ tasks[i].proc = -1; /* Invalidate. */
+ z = tasks[i].zone;
+ break;
+ }
+ }
+
+ if (z == 0) {
+ fprintf(stderr, "error: Failed to find zone for finished "
+ "zone compilation process.\n");
+ return 1;
+ }
+
+ /* Evaluate. */
+ if (!WIFEXITED(rc)) {
+ fprintf(stderr, "error: Compilation of '%s' "
+ "failed, process was killed.\n",
+ z->name);
+ return 1;
+ } else {
+ if (rc < 0 || WEXITSTATUS(rc) != 0) {
+ fprintf(stderr, "error: Compilation of "
+ "'%s' failed, knot-zcompile "
+ "return code was '%d'\n",
+ z->name, WEXITSTATUS(rc));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*! \brief Register running zone compilation process. */
+int zctask_add(knotc_zctask_t *tasks, int count, pid_t pid, conf_zone_t *zone)
+{
+ /* Find free space. */
+ for (unsigned i = 0; i < count; ++i) {
+ if (tasks[i].proc == -1) {
+ tasks[i].proc = pid;
+ tasks[i].zone = zone;
+ return 0;
+ }
+ }
+
+ /* Free space not found. */
+ return -1;
+}
+
+/*!
+ * \brief Execute specified action.
+ *
+ * \param action Action to be executed (start, stop, restart...)
+ * \param argv Additional arguments vector.
+ * \param argc Addition arguments count.
+ * \param pid Specified PID for action.
+ * \param verbose True if running in verbose mode.
+ * \param force True if forced operation is required.
+ * \param wait Wait for the operation to finish.
+ * \param interactive Interactive mode.
+ * \param jobs Number of parallel tasks to run.
+ * \param pidfile Specified PID file for action.
+ *
+ * \retval 0 on success.
+ * \retval error return code for main on error.
+ *
+ * \todo Make enumerated flags instead of many parameters...
+ */
+int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
+ int force, int wait, int interactive, int jobs, const char *pidfile)
+{
+ int valid_cmd = 0;
+ int rc = 0;
+ if (strcmp(action, "start") == 0) {
+
+ // Check PID
+ valid_cmd = 1;
+// if (pid < 0 && pid == KNOT_ERANGE) {
+// fprintf(stderr, "control: Another server instance "
+// "is already starting.\n");
+// return 1;
+// }
+ if (pid > 0 && pid_running(pid)) {
+
+ fprintf(stderr, "control: Server PID found, "
+ "already running.\n");
+
+ if (!force) {
+ return 1;
+ } else {
+ fprintf(stderr, "control: forcing "
+ "server start, killing old pid=%ld.\n",
+ (long)pid);
+ kill(pid, SIGKILL);
+ pid_remove(pidfile);
+ }
+ }
+
+ // Lock configuration
+ conf_read_lock();
+
+ // Prepare command
+ const char *cfg = conf()->filename;
+ const char *args[] = {
+ PROJECT_EXEC,
+ interactive ? "" : "-d",
+ cfg ? "-c" : "",
+ cfg ? cfg : "",
+ verbose ? "-v" : "",
+ argc > 0 ? argv[0] : ""
+ };
+
+ // Unlock configuration
+ conf_read_unlock();
+
+ // Execute command
+ if (interactive) {
+ printf("control: Running in interactive mode.\n");
+ fflush(stderr);
+ fflush(stdout);
+ }
+ if ((rc = exec_cmd(args, 6)) < 0) {
+ pid_remove(pidfile);
+ rc = 1;
+ }
+ fflush(stderr);
+ fflush(stdout);
+
+ // Wait for finish
+ if (wait && !interactive) {
+ if (verbose) {
+ fprintf(stdout, "control: waiting for server "
+ "to load.\n");
+ }
+ /* Periodically read pidfile and wait for
+ * valid result. */
+ pid = 0;
+ while(pid == 0 || !pid_running(pid)) {
+ pid = pid_read(pidfile);
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 500 * 1000;
+ select(0, 0, 0, 0, &tv);
+ }
+ }
+ }
+ if (strcmp(action, "stop") == 0) {
+
+ // Check PID
+ valid_cmd = 1;
+ rc = 0;
+ if (pid <= 0 || !pid_running(pid)) {
+ fprintf(stderr, "Server PID not found, "
+ "probably not running.\n");
+
+ if (!force) {
+ rc = 1;
+ } else {
+ fprintf(stderr, "control: forcing "
+ "server stop.\n");
+ }
+ }
+
+ // Stop
+ if (rc == 0) {
+ if (kill(pid, SIGTERM) < 0) {
+ pid_remove(pidfile);
+ rc = 1;
+ }
+ }
+
+ // Wait for finish
+ if (rc == 0 && wait) {
+ if (verbose) {
+ fprintf(stdout, "control: waiting for server "
+ "to stop.\n");
+ }
+ /* Periodically read pidfile and wait for
+ * valid result. */
+ while(pid_running(pid)) {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 500 * 1000;
+ select(0, 0, 0, 0, &tv);
+ }
+ }
+ }
+ if (strcmp(action, "restart") == 0) {
+ valid_cmd = 1;
+ execute("stop", argv, argc, pid, verbose, force, wait,
+ interactive, jobs, pidfile);
+
+ int i = 0;
+ while((pid = pid_read(pidfile)) > 0) {
+
+ if (!pid_running(pid)) {
+ pid_remove(pidfile);
+ break;
+ }
+ if (i == WAITPID_TIMEOUT) {
+ fprintf(stderr, "Timeout while "
+ "waiting for the server to finish.\n");
+ //pid_remove(pidfile);
+ break;
+ } else {
+ sleep(1);
+ ++i;
+ }
+ }
+
+ printf("Restarting server.\n");
+ rc = execute("start", argv, argc, -1, verbose, force, wait,
+ interactive, jobs, pidfile);
+ }
+ if (strcmp(action, "reload") == 0) {
+
+ // Check PID
+ valid_cmd = 1;
+ if (pid <= 0 || !pid_running(pid)) {
+ fprintf(stderr, "Server PID not found, "
+ "probably not running.\n");
+
+ if (force) {
+ fprintf(stderr, "control: forcing "
+ "server stop.\n");
+ } else {
+ return 1;
+ }
+ }
+
+ // Stop
+ if (kill(pid, SIGHUP) < 0) {
+ pid_remove(pidfile);
+ rc = 1;
+ }
+ }
+ if (strcmp(action, "running") == 0) {
+
+ // Check PID
+ valid_cmd = 1;
+ if (pid <= 0) {
+ printf("Server PID not found, "
+ "probably not running.\n");
+ rc = 1;
+ } else {
+ if (!pid_running(pid)) {
+ printf("Server PID not found, "
+ "probably not running.\n");
+ fprintf(stderr,
+ "warning: PID file is stale.\n");
+ } else {
+ printf("Server running as PID %ld.\n",
+ (long)pid);
+ }
+ rc = 0;
+ }
+ }
+ if (strcmp(action, "compile") == 0) {
+
+ // Print job count
+ if (jobs > 1) {
+ printf("warning: Will attempt to compile %d zones "
+ "in parallel, this increases memory consumption "
+ "for large zones.\n", jobs);
+ }
+
+ // Check zone
+ valid_cmd = 1;
+
+ // Lock configuration
+ conf_read_lock();
+
+ // Generate databases for all zones
+ node *n = 0;
+ int running = 0;
+ knotc_zctask_t *tasks = zctask_create(jobs);
+ WALK_LIST(n, conf()->zones) {
+
+ // Fetch zone
+ conf_zone_t *zone = (conf_zone_t*)n;
+
+ // Check source files and mtime
+ int zone_status = check_zone(zone->db, zone->file);
+ if (zone_status == KNOTD_EOK) {
+ printf("Zone '%s' is up-to-date.\n",
+ zone->name);
+
+ if (force) {
+ fprintf(stderr, "control: forcing "
+ "zone recompilation.\n");
+ } else {
+ continue;
+ }
+ }
+
+ // Check for not existing source
+ if (zone_status == KNOTD_ENOENT) {
+ continue;
+ }
+
+ /* Evaluate space for new task. */
+ if (running == jobs) {
+ zctask_wait(tasks, jobs);
+ --running;
+ }
+
+ const char *args[] = {
+ ZONEPARSER_EXEC,
+ zone->enable_checks ? "-s" : "",
+ verbose ? "-v" : "",
+ "-o",
+ zone->db,
+ zone->name,
+ zone->file
+ };
+
+ // Execute command
+ if (verbose) {
+ printf("Compiling '%s' as '%s'...\n",
+ zone->name, zone->db);
+ }
+ fflush(stdout);
+ fflush(stderr);
+ pid_t zcpid = start_cmd(args, 7);
+ zctask_add(tasks, jobs, zcpid, zone);
+ ++running;
+ }
+
+ /* Wait for all running tasks. */
+ while (running > 0) {
+ zctask_wait(tasks, jobs);
+ --running;
+ }
+ free(tasks);
+
+ // Unlock configuration
+ conf_read_unlock();
+ }
+ if (!valid_cmd) {
+ fprintf(stderr, "Invalid command: '%s'\n", action);
+ return 1;
+ }
+
+ // Log
+ if (verbose) {
+ printf("'%s' finished (return code %d)\n", action, rc);
+ }
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+ // Parse command line arguments
+ int c = 0, li = 0;
+ int force = 0;
+ int verbose = 0;
+ int wait = 0;
+ int interactive = 0;
+ int jobs = 1;
+ const char* config_fn = 0;
+
+ /* Long options. */
+ struct option opts[] = {
+ {"wait", no_argument, 0, 'w'},
+ {"force", no_argument, 0, 'f'},
+ {"config", required_argument, 0, 'c'},
+ {"verbose", no_argument, 0, 'v'},
+ {"interactive", no_argument, 0, 'i'},
+ {"jobs", required_argument, 0, 'c'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ while ((c = getopt_long(argc, argv, "wfc:vij:Vh", opts, &li)) != -1) {
+ switch (c)
+ {
+ case 'w':
+ wait = 1;
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case 'c':
+ config_fn = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'i':
+ interactive = 1;
+ break;
+ case 'j':
+ jobs = atoi(optarg);
+ if (jobs < 1) {
+ fprintf(stderr, "Invalid parameter '%s' to "
+ "'-j', expects number <1..n>\n",
+ optarg);
+ help(argc, argv);
+ return 1;
+ }
+ break;
+ case 'V':
+ printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION);
+ return 0;
+ case 'h':
+ case '?':
+ default:
+ help(argc, argv);
+ return 1;
+ }
+ }
+
+ // Check if there's at least one remaining non-option
+ if (argc - optind < 1) {
+ help(argc, argv);
+ return 1;
+ }
+
+ // Initialize log (no output)
+ log_init();
+ log_levels_set(LOGT_SYSLOG, LOG_ANY, 0);
+ log_levels_set(LOGT_STDOUT, LOG_ANY, 0);
+ closelog();
+
+ // Find implicit configuration file
+ char *default_fn = 0;
+ if (!config_fn) {
+ default_fn = conf_find_default();
+ config_fn = default_fn;
+ }
+
+ // Open configuration
+ if (conf_open(config_fn) != 0) {
+ fprintf(stderr, "Failed to parse configuration '%s'.\n",
+ config_fn);
+ free(default_fn);
+ return 1;
+ }
+
+ // Free default config filename if exists
+ free(default_fn);
+
+ // Verbose mode
+ if (verbose) {
+ int mask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_DEBUG);
+ log_levels_add(LOGT_STDOUT, LOG_ANY, mask);
+ }
+
+ // Fetch PID
+ char* pidfile = pid_filename();
+ if (!pidfile) {
+ fprintf(stderr, "No configuration found, "
+ "please specify with '-c' parameter.\n");
+ log_close();
+ return 1;
+ }
+
+ pid_t pid = pid_read(pidfile);
+
+ // Actions
+ const char* action = argv[optind];
+
+ // Execute action
+ int rc = execute(action, argv + optind + 1, argc - optind - 1,
+ pid, verbose, force, wait, interactive, jobs, pidfile);
+
+ // Finish
+ free(pidfile);
+ log_close();
+ return rc;
+}
diff --git a/src/knot/ctl/process.c b/src/knot/ctl/process.c
new file mode 100644
index 0000000..e46fa37
--- /dev/null
+++ b/src/knot/ctl/process.c
@@ -0,0 +1,126 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+
+#include "knot/common.h"
+#include "knot/ctl/process.h"
+#include "knot/conf/conf.h"
+#include "knot/other/error.h"
+
+char* pid_filename()
+{
+ conf_read_lock();
+
+ /* Read configuration. */
+ char* ret = 0;
+ if (conf()) {
+ ret = strdup(conf()->pidfile);
+ }
+
+ conf_read_unlock();
+
+ return ret;
+}
+
+pid_t pid_read(const char* fn)
+{
+ char buf[64];
+
+ if (fn) {
+ FILE *fp = fopen(fn, "r");
+ if (!fp) {
+ return KNOTD_ENOENT;
+ }
+
+ int readb = 0;
+ int rc = fread(buf, 1, 1, fp);
+ while (rc > 0) {
+ if (++readb == sizeof(buf) - 1) {
+ break;
+ }
+ rc = fread(buf + readb, 1, 1, fp);
+ }
+ buf[readb] = '\0';
+ fclose(fp);
+
+ // Check read result
+ if (readb < 1) {
+ return KNOTD_ENOENT;
+ }
+
+ // Convert pid
+ char* ep = 0;
+ unsigned long pid = strtoul(buf, &ep, 10);
+ if ((errno == ERANGE) || (*ep && !isspace(*ep))) {
+ return KNOTD_ERANGE;
+ }
+
+ return (pid_t)pid;
+ }
+
+ return KNOTD_EINVAL;
+}
+
+int pid_write(const char* fn)
+{
+ if (!fn) {
+ return KNOTD_EINVAL;
+ }
+
+ // Convert
+ char buf[64];
+ int wbytes = 0;
+ wbytes = snprintf(buf, sizeof(buf), "%lu", (unsigned long) getpid());
+ if (wbytes < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Write
+ FILE *fp = fopen(fn, "w");
+ if (fp) {
+ int rc = fwrite(buf, wbytes, 1, fp);
+ fclose(fp);
+ if (rc < 0) {
+ return KNOTD_ERROR;
+ }
+
+ return 0;
+ }
+
+ return KNOTD_ENOENT;
+}
+
+int pid_remove(const char* fn)
+{
+ if (unlink(fn) < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ return KNOTD_EOK;
+}
+
+int pid_running(pid_t pid)
+{
+ return kill(pid, 0) == 0;
+}
+
diff --git a/src/knot/ctl/process.h b/src/knot/ctl/process.h
new file mode 100644
index 0000000..d8f2f4c
--- /dev/null
+++ b/src/knot/ctl/process.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file process.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Functions for POSIX process handling.
+ *
+ * \addtogroup ctl
+ * @{
+ */
+
+#ifndef _KNOTD_PROCESS_H_
+#define _KNOTD_PROCESS_H_
+
+#include <unistd.h>
+
+/*!
+ * \brief Return a filename of the default compiled database file.
+ *
+ * \retval Filename of the database file.
+ * \retval NULL if not exists.
+ */
+char* pid_filename();
+
+/*!
+ * \brief Read PID from given file.
+ *
+ * \param fn Filename containing PID.
+ *
+ * \retval PID on success (positive integer).
+ * \retval KNOTD_EINVAL on null path.
+ * \retval KNOTD_ENOENT if the filename content cannot be read.
+ * \retval KNOTD_ERANGE if the stored PID is out of range.
+ */
+pid_t pid_read(const char* fn);
+
+/*!
+ * \brief Write PID to given file.
+ *
+ * \param fn Filename containing PID.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on null path.
+ * \retval KNOTD_ENOENT filename cannot be opened for writing.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int pid_write(const char* fn);
+
+/*!
+ * \brief Remove file containing PID.
+ *
+ * \param fn Filename containing PID.
+ *
+ * \warning Filename content won't be checked.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL failed to remove filename.
+ */
+int pid_remove(const char* fn);
+
+/*!
+ * \brief Return true if the PID is running.
+ *
+ * \param pid Process ID.
+ *
+ * \retval 1 if running.
+ * \retval 0 if not running (or error).
+ */
+int pid_running(pid_t pid);
+
+#endif // _KNOTD_PROCESS_H_
+
+/*! @} */
diff --git a/src/knot/main.c b/src/knot/main.c
new file mode 100644
index 0000000..4091055
--- /dev/null
+++ b/src/knot/main.c
@@ -0,0 +1,336 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "common.h"
+
+#include "knot/common.h"
+#include "knot/other/error.h"
+#include "knot/server/server.h"
+#include "zcompile/zcompile.h"
+#include "knot/ctl/process.h"
+#include "knot/conf/conf.h"
+#include "knot/conf/logconf.h"
+#include "common/evqueue.h"
+#include "knot/server/zones.h"
+
+/*----------------------------------------------------------------------------*/
+
+/* Signal flags. */
+static volatile short sig_req_stop = 0;
+static volatile short sig_req_reload = 0;
+static volatile short sig_stopping = 0;
+
+// SIGINT signal handler
+void interrupt_handle(int s)
+{
+ // Reload configuration
+ if (s == SIGHUP) {
+ sig_req_reload = 1;
+ return;
+ }
+
+ // Stop server
+ if (s == SIGINT || s == SIGTERM) {
+ if (sig_stopping == 0) {
+ sig_req_stop = 1;
+ sig_stopping = 1;
+ } else {
+ log_server_notice("OK! Exiting immediately.\n");
+ exit(1);
+ }
+ }
+}
+
+void help(int argc, char **argv)
+{
+ printf("Usage: %sd [parameters]\n",
+ PACKAGE_NAME);
+ printf("Parameters:\n"
+ " -c, --config [file] Select configuration file.\n"
+ " -d, --daemonize Run server as a daemon.\n"
+ " -v, --verbose Verbose mode - additional runtime information.\n"
+ " -V, --version Print version of the server.\n"
+ " -h, --help Print help and usage.\n");
+}
+
+int main(int argc, char **argv)
+{
+ // Parse command line arguments
+ int c = 0, li = 0;
+ int verbose = 0;
+ int daemonize = 0;
+ char* config_fn = 0;
+
+ /* Long options. */
+ struct option opts[] = {
+ {"config", required_argument, 0, 'c'},
+ {"daemonize", no_argument, 0, 'd'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ while ((c = getopt_long(argc, argv, "c:dvVh", opts, &li)) != -1) {
+ switch (c)
+ {
+ case 'c':
+ config_fn = strdup(optarg);
+ break;
+ case 'd':
+ daemonize = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'V':
+ printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION);
+ return 0;
+ case 'h':
+ case '?':
+ default:
+ help(argc, argv);
+ return 1;
+ }
+ }
+
+ // Now check if we want to daemonize
+ if (daemonize) {
+ if (daemon(1, 0) != 0) {
+ fprintf(stderr, "Daemonization failed, "
+ "shutting down...\n");
+ return 1;
+ }
+ }
+
+ // Register service and signal handler
+ struct sigaction emptyset;
+ emptyset.sa_handler = interrupt_handle;
+ sigemptyset(&emptyset.sa_mask);
+ emptyset.sa_flags = 0;
+ sigaction(SIGALRM, &emptyset, NULL); // Interrupt
+
+ // Setup event queue
+ evqueue_set(evqueue_new());
+
+ // Initialize log
+ log_init();
+
+ // Verbose mode
+ if (verbose) {
+ int mask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_DEBUG);
+ log_levels_add(LOGT_STDOUT, LOG_ANY, mask);
+ }
+
+ // Initialize pseudorandom number generator
+ srand(time(0));
+
+ // Create server
+ server_t *server = server_create();
+
+ // Initialize configuration
+ conf_read_lock();
+ conf_add_hook(conf(), CONF_LOG, log_conf_hook, 0);
+ conf_add_hook(conf(), CONF_LOG, zones_ns_conf_hook, server->nameserver);
+ conf_add_hook(conf(), CONF_LOG, server_conf_hook, server);
+ conf_read_unlock();
+
+ // Find implicit configuration file
+ if (!config_fn) {
+ config_fn = conf_find_default();
+ }
+
+ // Find absolute path for config file
+ if (config_fn[0] != '/')
+ {
+ // Get absolute path to cwd
+ size_t cwbuflen = 64;
+ char *cwbuf = malloc((cwbuflen + 2) * sizeof(char));
+ while (getcwd(cwbuf, cwbuflen) == 0) {
+ cwbuflen *= 2;
+ cwbuf = realloc(cwbuf, (cwbuflen + 2) * sizeof(char));
+ }
+ cwbuflen = strlen(cwbuf);
+
+ // Append ending slash
+ if (cwbuf[cwbuflen - 1] != '/') {
+ cwbuf = strcat(cwbuf, "/");
+ }
+
+ // Assemble path to config file
+ char *abs_cfg = strcdup(cwbuf, config_fn);
+ free(config_fn);
+ free(cwbuf);
+ config_fn = abs_cfg;
+ }
+
+ // Open configuration
+ log_server_info("Parsing configuration '%s' ...\n", config_fn);
+ if (conf_open(config_fn) != KNOTD_EOK) {
+
+ log_server_error("Failed to parse configuration file '%s'.\n",
+ config_fn);
+ server_destroy(&server);
+ free(config_fn);
+ return 1;
+ } else {
+ log_server_info("Configured %d interfaces and %d zones.\n",
+ conf()->ifaces_count, conf()->zones_count);
+ }
+ log_server_info("\n");
+
+ // Create server instance
+ char* pidfile = pid_filename();
+
+ // Run server
+ int res = 0;
+ log_server_info("Starting server...\n");
+ if ((res = server_start(server)) == KNOTD_EOK) {
+
+ // Save PID
+ int has_pid = 1;
+ int rc = pid_write(pidfile);
+ if (rc < 0) {
+ has_pid = 0;
+ log_server_warning("Failed to create "
+ "PID file '%s'.\n", pidfile);
+ }
+
+ // Change directory if daemonized
+ if (daemonize) {
+ log_server_info("Server started as a daemon, "
+ "PID = %ld\n", (long)getpid());
+ res = chdir("/");
+ } else {
+ log_server_info("Server started in foreground, "
+ "PID = %ld\n", (long)getpid());
+ }
+ if (has_pid) {
+ log_server_info("PID stored in %s\n", pidfile);
+ } else {
+ log_server_warning("Server running without PID file.\n");
+ }
+ size_t zcount = server->nameserver->zone_db->zone_count;
+ if (!zcount) {
+ log_server_warning("Server started, but no zones served.\n");
+ }
+
+ // Setup signal handler
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = interrupt_handle;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGHUP, &sa, NULL);
+ sa.sa_flags = 0;
+ pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL);
+
+ /* Run event loop. */
+ for(;;) {
+ pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
+ int ret = evqueue_poll(evqueue(), 0, 0);
+ pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL);
+
+ /* Interrupts. */
+ /*! \todo More robust way to exit evloop.
+ * Event loop should exit with a special
+ * event.
+ */
+ if (sig_req_stop) {
+ sig_req_stop = 0;
+ server_stop(server);
+ break;
+ }
+ if (sig_req_reload) {
+ log_server_info("Reloading configuration...\n");
+ sig_req_reload = 0;
+ int cf_ret = cf_ret = conf_open(config_fn);
+ switch (cf_ret) {
+ case KNOTD_EOK:
+ log_server_info("Configuration "
+ "reloaded.\n");
+ break;
+ case KNOTD_ENOENT:
+ log_server_error("Configuration "
+ "file '%s' "
+ "not found.\n",
+ conf()->filename);
+ break;
+ default:
+ log_server_error("Configuration "
+ "reload failed.\n");
+ break;
+ }
+ }
+
+ /* Events. */
+ if (ret > 0) {
+ event_t ev;
+ if (evqueue_get(evqueue(), &ev) == 0) {
+ dbg_server_verb("Event: "
+ "received new event.\n");
+ if (ev.cb) {
+ ev.cb(&ev);
+ }
+ }
+ }
+ }
+ pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
+
+ if ((res = server_wait(server)) != KNOTD_EOK) {
+ log_server_error("An error occured while "
+ "waiting for server to finish.\n");
+ } else {
+ log_server_info("Server finished.\n");
+ }
+
+ } else {
+ log_server_fatal("An error occured while "
+ "starting the server.\n");
+ }
+
+ // Stop server and close log
+ server_destroy(&server);
+
+ // Remove PID file
+ if (pid_remove(pidfile) < 0) {
+ log_server_warning("Failed to remove PID file.\n");
+ }
+
+ log_server_info("Shut down.\n");
+ log_close();
+ free(pidfile);
+
+ // Destroy event loop
+ evqueue_t *q = evqueue();
+ evqueue_free(&q);
+
+ // Free default config filename if exists
+ free(config_fn);
+
+ if (!daemonize) {
+ fflush(stdout);
+ fflush(stderr);
+ }
+
+ return res;
+}
diff --git a/src/knot/other/debug.h b/src/knot/other/debug.h
new file mode 100644
index 0000000..aa80373
--- /dev/null
+++ b/src/knot/other/debug.h
@@ -0,0 +1,426 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file other/debug.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Debugging facility, uses log.h.
+ *
+ * \addtogroup debugging
+ * @{
+ */
+
+#ifndef _KNOTD_DEBUG_H_
+#define _KNOTD_DEBUG_H_
+
+#include "config.h" /* autoconf generated */
+
+#include "knot/other/log.h"
+#include "common/print.h"
+
+/*! \todo Set these during configure as well. */
+//#define KNOTD_SERVER_DEBUG
+//#define KNOTD_THREADS_DEBUG
+//#define KNOTD_JOURNAL_DEBUG
+//#define KNOTD_NET_DEBUG
+//#define KNOTD_ZONES_DEBUG
+//#define KNOTD_XFR_DEBUG
+//#define KNOTD_NOTIFY_DEBUG
+//#define KNOTD_ZDUMP_DEBUG
+//#define KNOTD_ZLOAD_DEBUG
+
+/******************************************************************************/
+
+#ifdef KNOTD_NOTIFY_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_notify(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_notify_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_notify(msg...)
+#define dbg_notify_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_notify_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_notify_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_notify_verb(msg...)
+#define dbg_notify_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_notify_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_notify_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_notify_detail(msg...)
+#define dbg_notify_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_notify(msg...)
+#define dbg_notify_hex(data, len)
+#define dbg_notify_verb(msg...)
+#define dbg_notify_hex_verb(data, len)
+#define dbg_notify_detail(msg...)
+#define dbg_notify_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOTD_SERVER_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_server(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_server_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_server(msg...)
+#define dbg_server_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_server_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_server_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_server_verb(msg...)
+#define dbg_server_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_server_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_server_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_server_detail(msg...)
+#define dbg_server_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_server(msg...)
+#define dbg_server_hex(data, len)
+#define dbg_server_verb(msg...)
+#define dbg_server_hex_verb(data, len)
+#define dbg_server_detail(msg...)
+#define dbg_server_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOTD_NET_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_net(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_net_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_net(msg...)
+#define dbg_net_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_net_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_net_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_net_verb(msg...)
+#define dbg_net_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_net_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_net_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_net_detail(msg...)
+#define dbg_net_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_net(msg...)
+#define dbg_net_hex(data, len)
+#define dbg_net_verb(msg...)
+#define dbg_net_hex_verb(data, len)
+#define dbg_net_detail(msg...)
+#define dbg_net_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOTD_THREADS_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_dt(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_dt_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_dt(msg...)
+#define dbg_dt_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_dt_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_dt_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_dt_verb(msg...)
+#define dbg_dt_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_dt_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_dt_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_dt_detail(msg...)
+#define dbg_dt_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_dt(msg...)
+#define dbg_dt_hex(data, len)
+#define dbg_dt_verb(msg...)
+#define dbg_dt_hex_verb(data, len)
+#define dbg_dt_detail(msg...)
+#define dbg_dt_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOTD_JOURNAL_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_journal(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_journal_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_journal(msg...)
+#define dbg_journal_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_journal_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_journal_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_journal_verb(msg...)
+#define dbg_journal_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_journal_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_journal_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_journal_detail(msg...)
+#define dbg_journal_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_journal(msg...)
+#define dbg_journal_hex(data, len)
+#define dbg_journal_verb(msg...)
+#define dbg_journal_hex_verb(data, len)
+#define dbg_journal_detail(msg...)
+#define dbg_journal_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOTD_ZONES_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_zones(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zones_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#define dbg_zones_exec(cmds) do { cmds } while (0)
+#else
+#define dbg_zones(msg...)
+#define dbg_zones_hex(data, len)
+#define dbg_zones_exec(cmds)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_zones_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zones_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#define dbg_zones_exec_verb(cmds) do { cmds } while (0)
+#else
+#define dbg_zones_verb(msg...)
+#define dbg_zones_hex_verb(data, len)
+#define dbg_zones_exec_verb(cmds)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_zones_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zones_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#define dbg_zones_exec_detail(cmds) do { cmds } while (0)
+#else
+#define dbg_zones_detail(msg...)
+#define dbg_zones_hex_detail(data, len)
+#define dbg_zones_exec_detail(cmds)
+#endif
+
+/* No messages. */
+#else
+#define dbg_zones(msg...)
+#define dbg_zones_hex(data, len)
+#define dbg_zones_verb(msg...)
+#define dbg_zones_hex_verb(data, len)
+#define dbg_zones_detail(msg...)
+#define dbg_zones_hex_detail(data, len)
+#define dbg_zones_exec(cmds)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOTD_XFR_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_xfr(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_xfr_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_xfr(msg...)
+#define dbg_xfr_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_xfr_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_xfr_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_xfr_verb(msg...)
+#define dbg_xfr_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_xfr_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_xfr_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_xfr_detail(msg...)
+#define dbg_xfr_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_xfr(msg...)
+#define dbg_xfr_hex(data, len)
+#define dbg_xfr_verb(msg...)
+#define dbg_xfr_hex_verb(data, len)
+#define dbg_xfr_detail(msg...)
+#define dbg_xfr_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOTD_ZDUMP_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_zdump(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zdump_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_zdump(msg...)
+#define dbg_zdump_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_zdump_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zdump_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_zdump_verb(msg...)
+#define dbg_zdump_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_zdump_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zdump_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_zdump_detail(msg...)
+#define dbg_zdump_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_zdump(msg...)
+#define dbg_zdump_hex(data, len)
+#define dbg_zdump_verb(msg...)
+#define dbg_zdump_hex_verb(data, len)
+#define dbg_zdump_detail(msg...)
+#define dbg_zdump_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOTD_ZLOAD_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_zload(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zload_hex(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_zload(msg...)
+#define dbg_zload_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_zload_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zload_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_zload_verb(msg...)
+#define dbg_zload_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_zload_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+#define dbg_zload_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len))
+#else
+#define dbg_zload_detail(msg...)
+#define dbg_zload_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_zload(msg...)
+#define dbg_zload_hex(data, len)
+#define dbg_zload_verb(msg...)
+#define dbg_zload_hex_verb(data, len)
+#define dbg_zload_detail(msg...)
+#define dbg_zload_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#endif /* _KNOTD_DEBUG_H_ */
+
+/*! @} */
diff --git a/src/knot/other/error.c b/src/knot/other/error.c
new file mode 100644
index 0000000..a149966
--- /dev/null
+++ b/src/knot/other/error.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/other/error.h"
+#include "common/errors.h"
+
+const error_table_t knotd_error_msgs[] = {
+
+ /* Mapped errors. */
+ {KNOTD_EOK, "OK"},
+ {KNOTD_ENOMEM, "Not enough memory."},
+ {KNOTD_EINVAL, "Invalid parameter passed."},
+ {KNOTD_ENOTSUP, "Parameter not supported."},
+ {KNOTD_EBUSY, "Requested resource is busy."},
+ {KNOTD_EAGAIN, "The system lacked the necessary resource, try again."},
+ {KNOTD_EACCES, "Permission to perform requested operation is denied."},
+ {KNOTD_ECONNREFUSED, "Connection is refused."},
+ {KNOTD_EISCONN, "Already connected."},
+ {KNOTD_EADDRINUSE, "Address already in use."},
+ {KNOTD_ENOENT, "Resource not found."},
+ {KNOTD_ERANGE, "Value is out of range."},
+
+ /* Custom errors. */
+ {KNOTD_ERROR, "Generic error."},
+ {KNOTD_EZONEINVAL, "Invalid zone file."},
+ {KNOTD_ENOTRUNNING, "Resource is not running."},
+ {KNOTD_EPARSEFAIL, "Parser failed."},
+ {KNOTD_ENOIPV6, "IPv6 support disabled."},
+ {KNOTD_EMALF, "Malformed data."},
+ {KNOTD_ESPACE, "Not enough space provided."},
+ {KNOTD_EEXPIRED, "Resource is expired."},
+ {KNOTD_ERROR, 0}
+};
diff --git a/src/knot/other/error.h b/src/knot/other/error.h
new file mode 100644
index 0000000..65c51cf
--- /dev/null
+++ b/src/knot/other/error.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file other/error.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Error codes and function for getting error message.
+ *
+ * \addtogroup utils
+ * @{
+ */
+
+#ifndef _KNOTD__ERROR_H_
+#define _KNOTD__ERROR_H_
+
+#include <errno.h>
+
+#include "common/errors.h"
+
+/*!
+ * \brief Error codes used in the server.
+ *
+ * Some viable errors are directly mapped
+ * to libc errno codes.
+ */
+enum knot_error_t {
+
+ /* Directly mapped error codes. */
+ KNOTD_EOK = 0,
+ KNOTD_ENOMEM = -ENOMEM, /*!< \brief Out of memory. */
+ KNOTD_EINVAL = -EINVAL, /*!< \brief Invalid parameter passed. */
+ KNOTD_ENOTSUP = -ENOTSUP, /*!< \brief Parameter not supported. */
+ KNOTD_EBUSY = -EBUSY, /*!< \brief Requested resource is busy. */
+ KNOTD_EAGAIN = -EAGAIN, /*!< \brief OS lacked necessary resources. */
+ KNOTD_EACCES = -EACCES, /*!< \brief Permission is denied. */
+ KNOTD_ECONNREFUSED = -ECONNREFUSED, /*!< \brief Connection is refused. */
+ KNOTD_EISCONN = -EISCONN, /*!< \brief Already connected. */
+ KNOTD_EADDRINUSE = -EADDRINUSE, /*!< \brief Address already in use. */
+ KNOTD_ENOENT = -ENOENT, /*!< \brief Resource not found. */
+ KNOTD_ERANGE = -ERANGE, /*!< \brief Value is out of range. */
+
+ /* Custom error codes. */
+ KNOTD_ERROR = -16384, /*!< \brief Generic error. */
+ KNOTD_EZONEINVAL, /*!< \brief Invalid zone file. */
+ KNOTD_ENOTRUNNING, /*!< \brief Resource is not running. */
+ KNOTD_EPARSEFAIL, /*!< \brief Parser fail. */
+ KNOTD_ENOIPV6, /*!< \brief No IPv6 support. */
+ KNOTD_EMALF, /*!< \brief Malformed data. */
+ KNOTD_ESPACE, /*!< \brief Not enough space provided. */
+ KNOTD_EEXPIRED, /*!< \brief Resource is expired. */
+
+ KNOTD_ERROR_COUNT = 21
+};
+
+/*! \brief Table linking error messages to error codes. */
+extern const error_table_t knotd_error_msgs[KNOTD_ERROR_COUNT];
+
+/*!
+ * \brief Returns error message for the given error code.
+ *
+ * \param code Error code.
+ *
+ * \return String containing the error message.
+ */
+static inline const char *knotd_strerror(int code)
+{
+ return error_to_str((const error_table_t*)knotd_error_msgs, code);
+}
+
+/*!
+ * \brief errno mapper that automatically prepends fallback value.
+ *
+ * \see map_errno()
+ *
+ * \param err POSIX errno.
+ * \param ... List of handled codes.
+ *
+ * \return Mapped error code.
+ */
+#define knot_map_errno(err...) map_errno(KNOTD_ERROR, err);
+
+#endif /* _KNOTD__ERROR_H_ */
+
+/*! @} */
diff --git a/src/knot/other/log.c b/src/knot/other/log.c
new file mode 100644
index 0000000..9318d5f
--- /dev/null
+++ b/src/knot/other/log.c
@@ -0,0 +1,305 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "knot/common.h"
+#include "knot/other/error.h"
+#include "knot/other/log.h"
+#include "common/lists.h"
+#include "knot/conf/conf.h"
+
+/*! Log source table. */
+static uint8_t *LOG_FCL = 0;
+static volatile size_t LOG_FCL_SIZE = 0;
+static FILE** LOG_FDS = 0;
+static ssize_t LOG_FDS_OPEN = 0;
+
+#define facility_at(i) (LOG_FCL + ((i) << LOG_SRC_BITS))
+#define facility_next(f) (f) += (1 << LOG_SRC_BITS)
+#define facility_levels(f, i) *((f) + (i))
+
+int log_setup(int logfiles)
+{
+ /* Check facilities count. */
+ if (logfiles < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Ensure minimum facilities count. */
+ int facilities = LOGT_FILE + logfiles;
+
+ /* Reserve space for facilities. */
+ size_t new_size = facilities << LOG_SRC_BITS;
+ LOG_FDS = 0;
+ LOG_FDS_OPEN = 0;
+ LOG_FCL = 0;
+ LOG_FCL_SIZE = 0;
+ LOG_FCL = malloc(new_size);
+ if (!LOG_FCL) {
+ return KNOTD_ENOMEM;
+ }
+
+ /* Reserve space for logfiles. */
+ if (logfiles > 0) {
+ LOG_FDS = malloc(sizeof(FILE*) * logfiles);
+ if (!LOG_FDS) {
+ free(LOG_FCL);
+ LOG_FCL = 0;
+ return KNOTD_ENOMEM;
+ }
+ memset(LOG_FDS, 0, sizeof(FILE*) * logfiles);
+ }
+
+ memset(LOG_FCL, 0, new_size);
+ LOG_FCL_SIZE = new_size; // Assign only when all is set
+ return KNOTD_EOK;
+}
+
+
+
+int log_init()
+{
+ /* Initialize globals. */
+ LOG_FCL = 0;
+ LOG_FCL_SIZE = 0;
+ LOG_FDS = 0;
+ LOG_FDS_OPEN = 0;
+
+ /* Setup initial state. */
+ int ret = KNOTD_EOK;
+ int emask = LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR)|LOG_MASK(LOG_FATAL);
+ int imask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_NOTICE);
+
+ /* Add debug messages. */
+ emask |= LOG_MASK(LOG_DEBUG);
+
+ ret = log_setup(0);
+ log_levels_set(LOGT_SYSLOG, LOG_ANY, emask);
+ log_levels_set(LOGT_STDERR, LOG_ANY, emask);
+ log_levels_set(LOGT_STDOUT, LOG_ANY, imask);
+
+ /// \todo May change to LOG_DAEMON.
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ openlog(PACKAGE_NAME, LOG_PID, LOG_DAEMON);
+ return ret;
+}
+
+void log_close()
+{
+ log_truncate();
+ closelog();
+}
+
+void log_truncate()
+{
+ LOG_FCL_SIZE = 0;
+ if (LOG_FCL) {
+ free(LOG_FCL);
+ LOG_FCL = 0;
+ }
+ if (LOG_FDS) {
+
+ /* Close open logfiles. */
+ for (int i = 0; i < LOG_FDS_OPEN; ++i) {
+ fclose(LOG_FDS[i]);
+ }
+
+ free(LOG_FDS);
+ LOG_FDS = 0;
+ LOG_FDS_OPEN = 0;
+ }
+}
+
+int log_isopen()
+{
+ return LOG_FCL_SIZE;
+}
+
+int log_open_file(const char* filename)
+{
+ // Check facility
+ if (unlikely(!LOG_FCL_SIZE || LOGT_FILE + LOG_FDS_OPEN >= LOG_FCL_SIZE)) {
+ return KNOTD_ERROR;
+ }
+
+ // Open file
+ LOG_FDS[LOG_FDS_OPEN] = fopen(filename, "w");
+ if (!LOG_FDS[LOG_FDS_OPEN]) {
+ return KNOTD_EINVAL;
+ }
+
+ // Disable buffering
+ setvbuf(LOG_FDS[LOG_FDS_OPEN], (char *)0, _IONBF, 0);
+
+ return LOGT_FILE + LOG_FDS_OPEN++;
+}
+
+uint8_t log_levels(int facility, logsrc_t src)
+{
+ // Check facility
+ if (unlikely(!LOG_FCL_SIZE || facility >= LOG_FCL_SIZE)) {
+ return 0;
+ }
+
+ return *(LOG_FCL + (facility << LOG_SRC_BITS) + src);
+}
+
+int log_levels_set(int facility, logsrc_t src, uint8_t levels)
+{
+ // Check facility
+ if (unlikely(!LOG_FCL_SIZE || facility >= LOG_FCL_SIZE)) {
+ return KNOTD_EINVAL;
+ }
+
+ // Get facility pointer from offset
+ uint8_t *lp = LOG_FCL + (facility << LOG_SRC_BITS);
+
+ // Assign level if not multimask
+ if (src != LOG_ANY) {
+ *(lp + src) = levels;
+ } else {
+ // Any == set to all sources
+ for (int i = 0; i <= LOG_ANY; ++i) {
+ *(lp + i) = levels;
+ }
+ }
+
+ return KNOTD_EOK;
+}
+
+int log_levels_add(int facility, logsrc_t src, uint8_t levels)
+{
+ uint8_t new_levels = log_levels(facility, src) | levels;
+ return log_levels_set(facility, src, new_levels);
+}
+
+static int _log_msg(logsrc_t src, int level, const char *msg)
+{
+ if(!log_isopen()) {
+ return KNOTD_ERROR;
+ }
+
+ int ret = 0;
+ FILE *stream = stdout;
+ uint8_t *f = facility_at(LOGT_SYSLOG);
+
+ // Syslog
+ if (facility_levels(f, src) & LOG_MASK(level)) {
+ syslog(level, "%s", msg);
+ ret = 1; // To prevent considering the message as ignored.
+ }
+
+ // Convert level to mask
+ level = LOG_MASK(level);
+
+ // Log streams
+ for (int i = LOGT_STDERR; i < LOGT_FILE + LOG_FDS_OPEN; ++i) {
+
+ // Check facility levels mask
+ f = facility_at(i);
+ if (facility_levels(f, src) & level) {
+
+ // Select stream
+ switch(i) {
+ case LOGT_STDERR: stream = stderr; break;
+ case LOGT_STDOUT: stream = stdout; break;
+ default: stream = LOG_FDS[i - LOGT_FILE]; break;
+ }
+
+ // Print
+ ret = fprintf(stream, "%s", msg);
+ if (stream == stdout) {
+ fflush(stream);
+ }
+ }
+ }
+
+ if (ret < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ return ret;
+}
+
+int log_msg(logsrc_t src, int level, const char *msg, ...)
+{
+ /* Buffer for log message. */
+ char sbuf[4096];
+ char *buf = sbuf;
+ int buflen = sizeof(sbuf) - 1;
+
+ /* Prefix error level. */
+ const char *prefix = "";
+ switch (level) {
+ case LOG_DEBUG: break;
+ case LOG_INFO: break;
+ case LOG_NOTICE: prefix = "notice: "; break;
+ case LOG_WARNING: prefix = "warning: "; break;
+ case LOG_ERR: prefix = "error: "; break;
+ case LOG_FATAL: prefix = "fatal: "; break;
+ default: break;
+ }
+
+ /* Prepend prefix. */
+ int plen = strlen(prefix);
+ if (plen > 0) {
+ strcpy(buf, prefix);
+ buf += plen;
+ buflen -= plen;
+ }
+
+ /* Compile log message. */
+ int ret = 0;
+ va_list ap;
+ va_start(ap, msg);
+ ret = vsnprintf(buf, buflen, msg, ap);
+ va_end(ap);
+
+ /* Send to logging facilities. */
+ if (ret > 0) {
+ ret = _log_msg(src, level, sbuf);
+ }
+
+ return ret;
+}
+
+int log_vmsg(logsrc_t src, int level, const char *msg, va_list ap)
+{
+ int ret = 0;
+ char buf[2048];
+ ret = vsnprintf(buf, sizeof(buf) - 1, msg, ap);
+
+ if (ret > 0) {
+ ret = _log_msg(src, level, buf);
+ }
+
+ return ret;
+}
+
+void hex_log(int source, const char *data, int length)
+{
+ int ptr = 0;
+ for (; ptr < length; ptr++) {
+ log_msg(source, LOG_DEBUG, "0x%02x ",
+ (unsigned char)*(data + ptr));
+ }
+ log_msg(source, LOG_DEBUG, "\n");
+}
diff --git a/src/knot/other/log.h b/src/knot/other/log.h
new file mode 100644
index 0000000..305020c
--- /dev/null
+++ b/src/knot/other/log.h
@@ -0,0 +1,208 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file log.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Logging facility.
+ *
+ * \note Loglevel defined in syslog.h, may be redefined in other backend, but
+ * keep naming. LOG_FATAL, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG
+ *
+ * In standard mode, only LOG_FATAL, LOG_ERR and LOG_WARNING is logged.
+ * Verbose mode enables LOG_NOTICE and LOG_INFO for additional information.
+ *
+ * \addtogroup logging
+ * @{
+ */
+
+#ifndef _KNOTD_LOG_H_
+#define _KNOTD_LOG_H_
+
+/*
+ */
+#include <syslog.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+/*! \brief Log facility types. */
+typedef enum {
+ LOGT_SYSLOG = 0, /*!< Logging to syslog(3) facility. */
+ LOGT_STDERR = 1, /*!< Print log messages to the stderr. */
+ LOGT_STDOUT = 2, /*!< Print log messages to the stdout. */
+ LOGT_FILE = 3 /*!< Generic logging to (unbuffered) file on the disk. */
+} logtype_t;
+
+/*! \brief Log sources width (bits). */
+#define LOG_SRC_BITS 3
+
+/*! \brief Log sources (max. LOG_SRC_BITS bits). */
+typedef enum {
+ LOG_SERVER = 0, /*!< Server module. */
+ LOG_ANSWER = 1, /*!< Query answering module. */
+ LOG_ZONE = 2, /*!< Zone manipulation module. */
+ LOG_ANY = 7 /*!< Any module. */
+} logsrc_t;
+
+/*! \brief Severity mapping. */
+#define LOG_FATAL LOG_CRIT /*!< Fatal errors cannot be masked. */
+
+/* Logging facility setup. */
+
+/*!
+ * \brief Create logging facilities respecting their
+ * canonical order.
+ *
+ * Facilities ordering: Syslog, Stderr, Stdout, File0...
+ * \see logtype_t
+ *
+ * \param logfiles Number of extra logfiles.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid number of logfiles (negative).
+ */
+int log_setup(int logfiles);
+
+/*!
+ * \brief Setup logging subsystem.
+ *
+ * \see syslog.h
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_ENOMEM out of memory error.
+ */
+int log_init();
+
+/*!
+ * \brief Close and deinitialize log.
+ */
+void log_close();
+
+/*!
+ * \brief Truncate current log setup.
+ */
+void log_truncate();
+
+/*!
+ * \brief Return positive number if open.
+ *
+ * \return 1 if open (boolean true)
+ * \return 0 if closed (boolean false)
+ */
+int log_isopen();
+
+/*!
+ * \brief Open file as a logging facility.
+ *
+ * \param filename File path.
+ *
+ * \retval associated facility index on success.
+ * \retval KNOTD_EINVAL filename cannot be opened for writing.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int log_open_file(const char* filename);
+
+/*!
+ * \brief Return log levels for a given facility.
+ *
+ * \param facility Given log facility index.
+ * \param src Given log source in the context of current facility.
+ *
+ * \retval Associated log level flags on success.
+ * \retval 0 on error.
+ */
+uint8_t log_levels(int facility, logsrc_t src);
+
+/*!
+ * \brief Set log levels for given facility.
+ *
+ * \param facility Logging facility index (LOGT_SYSLOG...).
+ * \param src Logging source (LOG_SERVER...LOG_ANY).
+ * \param levels Bitmask of specified log levels.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters (facility out of range).
+ */
+int log_levels_set(int facility, logsrc_t src, uint8_t levels);
+
+/*!
+ * \brief Add log levels to a given facility.
+ *
+ * New levels are added on top of existing, the resulting
+ * levels set is "old_levels OR new_levels".
+ *
+ * \param facility Logging facility index (LOGT_SYSLOG...).
+ * \param src Logging source (LOG_SERVER...LOG_ANY).
+ * \param levels Bitmask of specified log levels.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters (facility out of range).
+ */
+int log_levels_add(int facility, logsrc_t src, uint8_t levels);
+
+/*!
+ * \brief Log message.
+ *
+ * Function follows printf() format.
+ *
+ * \param src Origin of the message.
+ * \param level Message error level.
+ * \param msg Content of the logged message.
+ *
+ * \retval Number of logged bytes on success.
+ * \retval 0 When the message is ignored.
+ * \retval KNOTD_EINVAL invalid parameters.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int log_msg(logsrc_t src, int level, const char *msg, ...)
+ __attribute__((format(printf, 3, 4)));
+
+/*!
+ * \brief Log message for stdarg.
+ *
+ * \see log_msg
+ */
+int log_vmsg(logsrc_t src, int level, const char *msg, va_list ap);
+
+void hex_log(int source, const char *data, int length);
+
+/* Convenient logging. */
+#define log_server_fatal(msg...) log_msg(LOG_SERVER, LOG_FATAL, msg)
+#define log_server_error(msg...) log_msg(LOG_SERVER, LOG_ERR, msg)
+#define log_server_warning(msg...) log_msg(LOG_SERVER, LOG_WARNING, msg)
+#define log_server_notice(msg...) log_msg(LOG_SERVER, LOG_NOTICE, msg)
+#define log_server_info(msg...) log_msg(LOG_SERVER, LOG_INFO, msg)
+#define log_server_debug(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg)
+
+#define log_answer_fatal(msg...) log_msg(LOG_ANSWER, LOG_FATAL, msg)
+#define log_answer_error(msg...) log_msg(LOG_ANSWER, LOG_ERR, msg)
+#define log_answer_warning(msg...) log_msg(LOG_ANSWER, LOG_WARNING, msg)
+#define log_answer_notice(msg...) log_msg(LOG_ANSWER, LOG_NOTICE, msg)
+#define log_answer_info(msg...) log_msg(LOG_ANSWER, LOG_INFO, msg)
+#define log_answer_debug(msg...) log_msg(LOG_ANSWER, LOG_DEBUG, msg)
+
+#define log_zone_fatal(msg...) log_msg(LOG_ZONE, LOG_FATAL, msg)
+#define log_zone_error(msg...) log_msg(LOG_ZONE, LOG_ERR, msg)
+#define log_zone_warning(msg...) log_msg(LOG_ZONE, LOG_WARNING, msg)
+#define log_zone_notice(msg...) log_msg(LOG_ZONE, LOG_NOTICE, msg)
+#define log_zone_info(msg...) log_msg(LOG_ZONE, LOG_INFO, msg)
+#define log_zone_debug(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg)
+
+#endif /* _KNOTD_LOG_H_ */
+
+/*! @} */
diff --git a/src/knot/server/dthreads.c b/src/knot/server/dthreads.c
new file mode 100644
index 0000000..9707e57
--- /dev/null
+++ b/src/knot/server/dthreads.c
@@ -0,0 +1,1006 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "knot/common.h"
+#include "knot/server/dthreads.h"
+#include "knot/other/log.h"
+#include "knot/other/error.h"
+
+/*! \brief Lock thread state for R/W. */
+static inline void lock_thread_rw(dthread_t *thread)
+{
+ pthread_mutex_lock(&thread->_mx);
+}
+/*! \brief Unlock thread state for R/W. */
+static inline void unlock_thread_rw(dthread_t *thread)
+{
+ pthread_mutex_unlock(&thread->_mx);
+}
+
+/*! \brief Signalize thread state change. */
+static inline void unit_signalize_change(dt_unit_t *unit)
+{
+ pthread_mutex_lock(&unit->_report_mx);
+ pthread_cond_signal(&unit->_report);
+ pthread_mutex_unlock(&unit->_report_mx);
+}
+
+/*!
+ * \brief Update thread state with notification.
+ * \param thread Given thread.
+ * \param state New state for thread.
+ * \retval 0 on success.
+ * \retval <0 on error (EINVAL, ENOTSUP).
+ */
+static inline int dt_update_thread(dthread_t *thread, int state)
+{
+ // Check
+ if (thread == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Cancel with lone thread
+ dt_unit_t *unit = thread->unit;
+ if (unit == 0) {
+ return KNOTD_ENOTSUP;
+ }
+
+ // Cancel current runnable if running
+ pthread_mutex_lock(&unit->_notify_mx);
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadIdle | ThreadActive)) {
+
+ // Update state
+ thread->state = state;
+ unlock_thread_rw(thread);
+
+ // Notify thread
+ dt_signalize(thread, SIGALRM);
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ } else {
+ /* Unable to update thread, it is already dead. */
+ unlock_thread_rw(thread);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ return KNOTD_EINVAL;
+ }
+
+ return KNOTD_EOK;
+}
+
+/*!
+ * \brief Thread entrypoint function.
+ *
+ * When a thread is created and started, it immediately enters this function.
+ * Depending on thread state, it either enters runnable or
+ * blocks until it is awakened.
+ *
+ * This function also handles "ThreadIdle" state to quickly suspend and resume
+ * threads and mitigate thread creation costs. Also, thread runnable may
+ * be changed to alter the thread behavior on runtime
+ */
+static void *thread_ep(void *data)
+{
+ // Check data
+ dthread_t *thread = (dthread_t *)data;
+ if (thread == 0) {
+ return 0;
+ }
+
+ // Check if is a member of unit
+ dt_unit_t *unit = thread->unit;
+ if (unit == 0) {
+ return 0;
+ }
+
+ // Ignore specific signals (except SIGALRM)
+ sigset_t ignset;
+ sigemptyset(&ignset);
+ sigaddset(&ignset, SIGINT);
+ sigaddset(&ignset, SIGTERM);
+ sigaddset(&ignset, SIGHUP);
+ pthread_sigmask(SIG_BLOCK, &ignset, 0); /*! \todo Review under BSD. */
+
+ dbg_dt("dthreads: [%p] entered ep\n", thread);
+
+ // Run loop
+ for (;;) {
+
+ // Check thread state
+ lock_thread_rw(thread);
+ if (thread->state == ThreadDead) {
+ dbg_dt("dthreads: [%p] marked as dead\n", thread);
+ unlock_thread_rw(thread);
+ break;
+ }
+
+ // Update data
+ thread->data = thread->_adata;
+ runnable_t _run = thread->run;
+
+ // Start runnable if thread is marked Active
+ if ((thread->state == ThreadActive) && (thread->run != 0)) {
+ unlock_thread_rw(thread);
+ dbg_dt("dthreads: [%p] entering runnable\n", thread);
+ _run(thread);
+ dbg_dt("dthreads: [%p] exited runnable\n", thread);
+ } else {
+ unlock_thread_rw(thread);
+ }
+
+ // If the runnable was cancelled, start new iteration
+ lock_thread_rw(thread);
+ if (thread->state & ThreadCancelled) {
+ dbg_dt("dthreads: [%p] cancelled\n", thread);
+ thread->state &= ~ThreadCancelled;
+ unlock_thread_rw(thread);
+ continue;
+ }
+ unlock_thread_rw(thread);
+
+ // Runnable finished without interruption, mark as Idle
+ pthread_mutex_lock(&unit->_notify_mx);
+ lock_thread_rw(thread);
+ if (thread->state & ThreadActive) {
+ thread->state &= ~ThreadActive;
+ thread->state |= ThreadIdle;
+ }
+
+ // Go to sleep if idle
+ if (thread->state & ThreadIdle) {
+ unlock_thread_rw(thread);
+
+ // Signalize state change
+ unit_signalize_change(unit);
+
+ // Wait for notification from unit
+ dbg_dt("dthreads: [%p] going idle\n", thread);
+ /*! \todo Check return value. */
+ pthread_cond_wait(&unit->_notify, &unit->_notify_mx);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ dbg_dt("dthreads: [%p] resumed from idle\n", thread);
+ } else {
+ unlock_thread_rw(thread);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ }
+ }
+
+ // Report thread state change
+ dbg_dt("dthreads: [%p] thread finished\n", thread);
+ unit_signalize_change(unit);
+ dbg_dt("dthreads: [%p] thread exited ep\n", thread);
+ lock_thread_rw(thread);
+ thread->state |= ThreadJoinable;
+ unlock_thread_rw(thread);
+
+ // Return
+ return 0;
+}
+
+/*!
+ * \brief Create single thread.
+ * \retval New thread instance on success.
+ * \retval NULL on error.
+ */
+static dthread_t *dt_create_thread(dt_unit_t *unit)
+{
+ // Alloc thread
+ dthread_t *thread = malloc(sizeof(dthread_t));
+ if (thread == 0) {
+ return 0;
+ }
+
+ memset(thread, 0, sizeof(dthread_t));
+
+ // Blank thread state
+ thread->state = ThreadJoined;
+ pthread_mutex_init(&thread->_mx, 0);
+
+ // Set membership in unit
+ thread->unit = unit;
+
+ // Initialize attribute
+ pthread_attr_t *attr = &thread->_attr;
+ pthread_attr_init(attr);
+ pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED);
+ pthread_attr_setschedpolicy(attr, SCHED_OTHER);
+ return thread;
+}
+
+/*! \brief Delete single thread. */
+static void dt_delete_thread(dthread_t **thread)
+{
+ // Check
+ if (thread == 0) {
+ return;
+ }
+ if (*thread == 0) {
+ return;
+ }
+
+ dthread_t* thr = *thread;
+ thr->unit = 0;
+ *thread = 0;
+
+ // Delete attribute
+ pthread_attr_destroy(&(thr)->_attr);
+
+ // Delete mutex
+ pthread_mutex_destroy(&(thr)->_mx);
+
+ // Free memory
+ free(thr);
+}
+
+/*
+ * Public APIs.
+ */
+
+dt_unit_t *dt_create(int count)
+{
+ // Check count
+ if (count <= 0) {
+ return 0;
+ }
+
+ dt_unit_t *unit = malloc(sizeof(dt_unit_t));
+ if (unit == 0) {
+ return 0;
+ }
+
+ // Initialize conditions
+ if (pthread_cond_init(&unit->_notify, 0) != 0) {
+ free(unit);
+ return 0;
+ }
+ if (pthread_cond_init(&unit->_report, 0) != 0) {
+ pthread_cond_destroy(&unit->_notify);
+ free(unit);
+ return 0;
+ }
+
+ // Initialize mutexes
+ if (pthread_mutex_init(&unit->_notify_mx, 0) != 0) {
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ free(unit);
+ return 0;
+ }
+ if (pthread_mutex_init(&unit->_report_mx, 0) != 0) {
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ pthread_mutex_destroy(&unit->_notify_mx);
+ free(unit);
+ return 0;
+ }
+ if (pthread_mutex_init(&unit->_mx, 0) != 0) {
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ pthread_mutex_destroy(&unit->_notify_mx);
+ pthread_mutex_destroy(&unit->_report_mx);
+ free(unit);
+ return 0;
+ }
+
+ // Save unit size
+ unit->size = count;
+
+ // Alloc threads
+ unit->threads = malloc(count * sizeof(dthread_t *));
+ if (unit->threads == 0) {
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ pthread_mutex_destroy(&unit->_notify_mx);
+ pthread_mutex_destroy(&unit->_report_mx);
+ pthread_mutex_destroy(&unit->_mx);
+ free(unit);
+ return 0;
+ }
+
+ // Initialize threads
+ int init_success = 1;
+ for (int i = 0; i < count; ++i) {
+ unit->threads[i] = dt_create_thread(unit);
+ if (unit->threads[i] == 0) {
+ init_success = 0;
+ break;
+ }
+ }
+
+ // Check thread initialization
+ if (!init_success) {
+
+ // Delete created threads
+ for (int i = 0; i < count; ++i) {
+ dt_delete_thread(&unit->threads[i]);
+ }
+
+ // Free rest of the unit
+ pthread_cond_destroy(&unit->_notify);
+ pthread_cond_destroy(&unit->_report);
+ pthread_mutex_destroy(&unit->_notify_mx);
+ pthread_mutex_destroy(&unit->_report_mx);
+ pthread_mutex_destroy(&unit->_mx);
+ free(unit->threads);
+ free(unit);
+ return 0;
+ }
+
+ return unit;
+}
+
+dt_unit_t *dt_create_coherent(int count, runnable_t runnable, void *data)
+{
+ // Check count
+ if (count <= 0) {
+ return 0;
+ }
+
+ // Create unit
+ dt_unit_t *unit = dt_create(count);
+ if (unit == 0) {
+ return 0;
+ }
+
+ // Set threads common purpose
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+
+ for (int i = 0; i < count; ++i) {
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ thread->run = runnable;
+ thread->_adata = data;
+ unlock_thread_rw(thread);
+ }
+
+ dt_unit_unlock(unit);
+ pthread_mutex_unlock(&unit->_notify_mx);
+
+ return unit;
+}
+
+void dt_delete(dt_unit_t **unit)
+{
+ /*
+ * All threads must be stopped or idle at this point,
+ * or else the behavior is undefined.
+ * Sorry.
+ */
+
+ // Check
+ if (unit == 0) {
+ return;
+ }
+ if (*unit == 0) {
+ return;
+ }
+
+ // Compact and reclaim idle threads
+ dt_unit_t *d_unit = *unit;
+ dt_compact(d_unit);
+
+ // Delete threads
+ for (int i = 0; i < d_unit->size; ++i) {
+ dt_delete_thread(&d_unit->threads[i]);
+ }
+
+ // Deinit mutexes
+ pthread_mutex_destroy(&d_unit->_notify_mx);
+ pthread_mutex_destroy(&d_unit->_report_mx);
+
+ // Deinit conditions
+ pthread_cond_destroy(&d_unit->_notify);
+ pthread_cond_destroy(&d_unit->_report);
+
+ // Free memory
+ free(d_unit->threads);
+ free(d_unit);
+ *unit = 0;
+}
+
+int dt_resize(dt_unit_t *unit, int size)
+{
+ // Check input
+ if (unit == 0 || size <= 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Evaluate delta
+ int delta = unit->size - size;
+
+ // Same size
+ if (delta == 0) {
+ return 0;
+ }
+
+ // Unit expansion
+ if (delta < 0) {
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+
+ // Realloc threads
+ dbg_dt("dthreads: growing from %d to %d threads\n",
+ unit->size, size);
+
+ dthread_t **threads = realloc(unit->threads,
+ size * sizeof(dthread_t *));
+ if (threads == NULL) {
+ dt_unit_unlock(unit);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ return -1;
+ }
+
+ // Reassign
+ unit->threads = threads;
+
+ // Create new threads
+ for (int i = unit->size; i < size; ++i) {
+ threads[i] = dt_create_thread(unit);
+ }
+
+ // Update unit
+ unit->size = size;
+ dt_unit_unlock(unit);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ return 0;
+ }
+
+
+ // Unit shrinking
+ int remaining = size;
+ dbg_dt("dthreads: shrinking from %d to %d threads\n",
+ unit->size, size);
+
+ // New threads vector
+ dthread_t **threads = malloc(size * sizeof(dthread_t *));
+ if (threads == 0) {
+ return KNOTD_ENOMEM;
+ }
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+
+ // Iterate while there is space in new unit
+ memset(threads, 0, size * sizeof(dthread_t *));
+ int threshold = ThreadActive;
+ for (;;) {
+
+ // Find threads matching given criterias
+ int inspected = 0;
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Get thread
+ dthread_t *thread = unit->threads[i];
+ if (thread == 0) {
+ continue;
+ }
+
+ // Count thread as inspected
+ ++inspected;
+
+ lock_thread_rw(thread);
+
+ // Populate with matching threads
+ if ((remaining > 0) &&
+ (!threshold || (thread->state & threshold))) {
+
+ // Append to new vector
+ threads[size - remaining] = thread;
+ --remaining;
+
+ // Invalidate in old vector
+ unit->threads[i] = 0;
+ dbg_dt_verb("dthreads: [%p] dt_resize: elected\n",
+ thread);
+
+ } else if (remaining <= 0) {
+
+ // Not enough space, delete thread
+ if (thread->state & ThreadDead) {
+ unlock_thread_rw(thread);
+ --inspected;
+ continue;
+ }
+
+ // Signalize thread to stop
+ thread->state = ThreadDead | ThreadCancelled;
+ dt_signalize(thread, SIGALRM);
+ dbg_dt_verb("dthreads: [%p] dt_resize: "
+ "is discarded\n", thread);
+ }
+
+ // Unlock thread and continue
+ unlock_thread_rw(thread);
+ }
+
+ // Finished inspecting running threads
+ if (inspected == 0) {
+ break;
+ }
+
+ // Lower threshold
+ switch (threshold) {
+ case ThreadActive:
+ threshold = ThreadIdle;
+ break;
+ case ThreadIdle:
+ threshold = ThreadDead;
+ break;
+ default:
+ threshold = ThreadJoined;
+ break;
+ }
+ }
+
+ // Notify idle threads to wake up
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+
+ // Join discarded threads
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Get thread
+ dthread_t *thread = unit->threads[i];
+ if (thread == 0) {
+ continue;
+ }
+
+ pthread_join(thread->_thr, 0);
+ thread->state = ThreadJoined;
+
+ // Delete thread
+ dt_delete_thread(&thread);
+ unit->threads[i] = 0;
+ }
+
+ // Reassign unit threads vector
+ unit->size = size;
+ free(unit->threads);
+ unit->threads = threads;
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+
+ return 0;
+}
+
+int dt_start(dt_unit_t *unit)
+{
+ // Check input
+ if (unit == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+ for (int i = 0; i < unit->size; ++i) {
+
+ dthread_t *thread = unit->threads[i];
+ int res = dt_start_id(thread);
+ if (res != 0) {
+ dbg_dt("dthreads: failed to create thread '%d'.", i);
+ dt_unit_unlock(unit);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ return res;
+ }
+
+ dbg_dt("dthreads: [%p] %s: thread started\n",
+ thread, __func__);
+ }
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ return 0;
+}
+
+int dt_start_id(dthread_t *thread)
+{
+ // Check input
+ if (thread == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ lock_thread_rw(thread);
+
+ // Update state
+ int prev_state = thread->state;
+ thread->state |= ThreadActive;
+ thread->state &= ~ThreadIdle;
+ thread->state &= ~ThreadDead;
+ thread->state &= ~ThreadJoined;
+ thread->state &= ~ThreadJoinable;
+
+ // Do not re-create running threads
+ if (prev_state != ThreadJoined) {
+ dbg_dt("dthreads: [%p] %s: refused to recreate thread\n",
+ thread, __func__);
+ unlock_thread_rw(thread);
+ return 0;
+ }
+
+ // Start thread
+ int res = pthread_create(&thread->_thr, /* pthread_t */
+ &thread->_attr, /* pthread_attr_t */
+ thread_ep, /* routine: thread_ep */
+ thread); /* passed object: dthread_t */
+
+ // Unlock thread
+ unlock_thread_rw(thread);
+ return res;
+}
+
+int dt_signalize(dthread_t *thread, int signum)
+{
+ // Check input
+ if (thread == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ int ret = pthread_kill(thread->_thr, signum);
+
+ /* Not thread id found or invalid signum. */
+ if (ret == EINVAL || ret == ESRCH) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Generic error. */
+ if (ret < 0) {
+ return KNOTD_ERROR;
+ }
+
+ return KNOTD_EOK;
+}
+
+int dt_join(dt_unit_t *unit)
+{
+ // Check input
+ if (unit == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ for (;;) {
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_report_mx);
+ dt_unit_lock(unit);
+
+ // Browse threads
+ int active_threads = 0;
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Count active or cancelled but pending threads
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadActive|ThreadCancelled)) {
+ ++active_threads;
+ }
+
+ // Reclaim dead threads, but only fast
+ if (thread->state & ThreadJoinable) {
+ unlock_thread_rw(thread);
+ dbg_dt_verb("dthreads: [%p] %s: reclaiming\n",
+ thread, __func__);
+ pthread_join(thread->_thr, 0);
+ dbg_dt("dthreads: [%p] %s: reclaimed\n",
+ thread, __func__);
+ thread->state = ThreadJoined;
+ } else {
+ unlock_thread_rw(thread);
+ }
+ }
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+
+ // Check result
+ if (active_threads == 0) {
+ pthread_mutex_unlock(&unit->_report_mx);
+ break;
+ }
+
+ // Wait for a thread to finish
+ pthread_cond_wait(&unit->_report, &unit->_report_mx);
+ pthread_mutex_unlock(&unit->_report_mx);
+ }
+
+ return KNOTD_EOK;
+}
+
+int dt_stop_id(dthread_t *thread)
+{
+ // Check input
+ if (thread == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Signalize active thread to stop
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadIdle | ThreadActive)) {
+ thread->state = ThreadDead | ThreadCancelled;
+ dt_signalize(thread, SIGALRM);
+ }
+ unlock_thread_rw(thread);
+
+ // Broadcast notification
+ dt_unit_t *unit = thread->unit;
+ if (unit != 0) {
+ pthread_mutex_lock(&unit->_notify_mx);
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ }
+
+ return KNOTD_EOK;
+}
+
+int dt_stop(dt_unit_t *unit)
+{
+ // Check unit
+ if (unit == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+
+ // Signalize all threads to stop
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Lock thread
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadIdle | ThreadActive)) {
+ thread->state = ThreadDead | ThreadCancelled;
+ dbg_dt("dthreads: [%p] %s: stopping thread\n",
+ thread, __func__);
+ dt_signalize(thread, SIGALRM);
+ }
+ unlock_thread_rw(thread);
+ }
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+
+ // Broadcast notification
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+
+ return KNOTD_EOK;
+}
+
+int dt_setprio(dthread_t *thread, int prio)
+{
+ // Check input
+ if (thread == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Clamp priority
+ int policy = SCHED_FIFO;
+ prio = MIN(MAX(sched_get_priority_min(policy), prio),
+ sched_get_priority_max(policy));
+
+ // Update scheduler policy
+ int ret = pthread_attr_setschedpolicy(&thread->_attr, policy);
+
+ // Update priority
+ if (ret >= 0) {
+ struct sched_param sp;
+ sp.sched_priority = prio;
+ ret = pthread_attr_setschedparam(&thread->_attr, &sp);
+ }
+
+ /* Map error codes. */
+ if (ret < 0) {
+ dbg_dt("dthreads: [%p] %s(%d): failed",
+ thread, __func__, prio);
+
+ /* Map "not supported". */
+ if (ret == ENOTSUP) {
+ return KNOTD_ENOTSUP;
+ }
+
+ return KNOTD_EINVAL;
+ }
+
+ return KNOTD_EOK;
+}
+
+int dt_repurpose(dthread_t *thread, runnable_t runnable, void *data)
+{
+ // Check
+ if (thread == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Stop here if thread isn't a member of a unit
+ dt_unit_t *unit = thread->unit;
+ if (unit == 0) {
+ lock_thread_rw(thread);
+ thread->state = ThreadActive | ThreadCancelled;
+ unlock_thread_rw(thread);
+ return KNOTD_ENOTSUP;
+ }
+
+ // Lock thread state changes
+ pthread_mutex_lock(&unit->_notify_mx);
+ lock_thread_rw(thread);
+
+ // Repurpose it's object and runnable
+ thread->run = runnable;
+ thread->_adata = data;
+
+ // Cancel current runnable if running
+ if (thread->state & (ThreadIdle | ThreadActive)) {
+
+ // Update state
+ thread->state = ThreadActive | ThreadCancelled;
+ unlock_thread_rw(thread);
+
+ // Notify thread
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ } else {
+ unlock_thread_rw(thread);
+ pthread_mutex_unlock(&unit->_notify_mx);
+ }
+
+ return KNOTD_EOK;
+}
+
+int dt_activate(dthread_t *thread)
+{
+ return dt_update_thread(thread, ThreadActive);
+}
+
+int dt_cancel(dthread_t *thread)
+{
+ return dt_update_thread(thread, ThreadIdle | ThreadCancelled);
+}
+
+int dt_compact(dt_unit_t *unit)
+{
+ // Check input
+ if (unit == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ // Lock unit
+ pthread_mutex_lock(&unit->_notify_mx);
+ dt_unit_lock(unit);
+
+ // Reclaim all Idle threads
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Locked state update
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadIdle)) {
+ thread->state = ThreadDead | ThreadCancelled;
+ dt_signalize(thread, SIGALRM);
+ }
+ unlock_thread_rw(thread);
+ }
+
+ // Notify all threads
+ pthread_cond_broadcast(&unit->_notify);
+ pthread_mutex_unlock(&unit->_notify_mx);
+
+ // Join all threads
+ for (int i = 0; i < unit->size; ++i) {
+
+ // Reclaim all dead threads
+ dthread_t *thread = unit->threads[i];
+ lock_thread_rw(thread);
+ if (thread->state & (ThreadDead)) {
+ dbg_dt_verb("dthreads: [%p] %s: reclaiming thread\n",
+ thread, __func__);
+ unlock_thread_rw(thread);
+ pthread_join(thread->_thr, 0);
+ dbg_dt("dthreads: [%p] %s: thread reclaimed\n",
+ thread, __func__);
+ thread->state = ThreadJoined;
+ } else {
+ unlock_thread_rw(thread);
+ }
+ }
+
+ dbg_dt_verb("dthreads: compact: joined all threads\n");
+
+ // Unlock unit
+ dt_unit_unlock(unit);
+
+ return KNOTD_EOK;
+}
+
+int dt_optimal_size()
+{
+#ifdef _SC_NPROCESSORS_ONLN
+ int ret = (int) sysconf(_SC_NPROCESSORS_ONLN);
+ if (ret >= 1) {
+ return ret + CPU_ESTIMATE_MAGIC;
+ }
+#endif
+ dbg_dt("dthreads: failed to fetch the number of online CPUs.");
+ return DEFAULT_THR_COUNT;
+}
+
+/*!
+ * \todo Use memory barriers or asynchronous read-only access, locking
+ * poses a thread performance decrease by 1.31%.
+ */
+
+int dt_is_cancelled(dthread_t *thread)
+{
+ // Check input
+ if (thread == 0) {
+ return 0;
+ }
+
+ lock_thread_rw(thread);
+ int ret = thread->state & ThreadCancelled;
+ unlock_thread_rw(thread);
+ return ret;
+}
+
+int dt_unit_lock(dt_unit_t *unit)
+{
+ // Check input
+ if (unit == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ int ret = pthread_mutex_lock(&unit->_mx);
+
+ /* Map errors. */
+ if (ret < 0) {
+ return knot_map_errno(EINVAL, EAGAIN);
+ }
+
+ return KNOTD_EOK;
+}
+
+int dt_unit_unlock(dt_unit_t *unit)
+{
+ // Check input
+ if (unit == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ int ret = pthread_mutex_unlock(&unit->_mx);
+
+ /* Map errors. */
+ if (ret < 0) {
+ return knot_map_errno(EINVAL, EAGAIN);
+ }
+
+ return KNOTD_EOK;
+}
diff --git a/src/knot/server/dthreads.h b/src/knot/server/dthreads.h
new file mode 100644
index 0000000..8a5e2b4
--- /dev/null
+++ b/src/knot/server/dthreads.h
@@ -0,0 +1,353 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file dthreads.h
+ *
+ * \author Marek Vavrusa <marek.vavusa@nic.cz>
+ *
+ * \brief Threading API.
+ *
+ * Dynamic threads provide:
+ * - coherent and incoherent threading capabilities
+ * - thread repurposing
+ * - thread prioritization
+ * - on-the-fly changing of threading unit size
+ *
+ * Coherent threading unit is when all threads execute
+ * the same runnable function.
+ *
+ * Incoherent function is when at least one thread executes
+ * a different runnable than the others.
+ *
+ * \addtogroup threading
+ * @{
+ */
+
+#ifndef _KNOTD_DTHREADS_H_
+#define _KNOTD_DTHREADS_H_
+
+#include <pthread.h>
+
+/* Forward decls */
+struct dthread_t;
+struct dt_unit_t;
+
+/*!
+ * \brief Thread state enumeration.
+ */
+typedef enum {
+ ThreadJoined = 1 << 0, /*!< Thread is finished and joined. */
+ ThreadJoinable = 1 << 1, /*!< Thread is waiting to be reclaimed. */
+ ThreadCancelled = 1 << 2, /*!< Thread is cancelled, finishing task. */
+ ThreadDead = 1 << 3, /*!< Thread is finished, exiting. */
+ ThreadIdle = 1 << 4, /*!< Thread is idle, waiting for purpose. */
+ ThreadActive = 1 << 5 /*!< Thread is active, working on a task. */
+
+} dt_state_t;
+
+/*!
+ * \brief Thread runnable prototype.
+ *
+ * Runnable is basically a pointer to function which is called on active
+ * thread runtime.
+ *
+ * \note When implementing a runnable, keep in mind to check thread state as
+ * it may change, and implement a cooperative cancellation point.
+ *
+ * Implement this by checking dt_is_cancelled() and return
+ * as soon as possible.
+ */
+typedef int (*runnable_t)(struct dthread_t *);
+
+/*!
+ * \brief Single thread descriptor public API.
+ */
+typedef struct dthread_t {
+ volatile unsigned state; /*!< Bitfield of dt_flag flags. */
+ runnable_t run; /*!< Runnable function or 0. */
+ void *data; /*!< Currently active data */
+ struct dt_unit_t *unit; /*!< Reference to assigned unit. */
+ void *_adata; /* Thread-specific data. */
+ pthread_t _thr; /* Thread */
+ pthread_attr_t _attr; /* Thread attributes */
+ pthread_mutex_t _mx; /* Thread state change lock. */
+} dthread_t;
+
+/*!
+ * \brief Thread unit descriptor API.
+ *
+ * Thread unit consists of 1..N threads.
+ * Unit is coherent if all threads execute
+ * the same runnable.
+ */
+typedef struct dt_unit_t {
+ int size; /*!< Unit width (number of threads) */
+ struct dthread_t **threads; /*!< Array of threads */
+ pthread_cond_t _notify; /* Notify thread */
+ pthread_mutex_t _notify_mx; /* Condition mutex */
+ pthread_cond_t _report; /* Report thread state */
+ pthread_mutex_t _report_mx; /* Condition mutex */
+ pthread_mutex_t _mx; /* Unit lock */
+} dt_unit_t;
+
+/*!
+ * \brief Create a set of threads with no initial runnable.
+ *
+ * \note All threads are created with Dead state.
+ * This means, they're not physically created unit dt_start() is called.
+ *
+ * \param count Requested thread count.
+ *
+ * \retval New instance if successful
+ * \retval NULL on error
+ */
+dt_unit_t *dt_create(int count);
+
+/*!
+ * \brief Create a set of coherent threads.
+ *
+ * Coherent means, that the threads will share a common runnable and the data.
+ *
+ * \param count Requested thread count.
+ * \param runnable Runnable function for all threads.
+ * \param data Any data passed onto threads.
+ *
+ * \retval New instance if successful
+ * \retval NULL on error
+ */
+dt_unit_t *dt_create_coherent(int count, runnable_t runnable, void *data);
+
+/*!
+ * \brief Free unit.
+ *
+ * \warning Behavior is undefined if threads are still active, make sure
+ * to call dt_join() first.
+ *
+ * \param unit Unit to be deleted.
+ */
+void dt_delete(dt_unit_t **unit);
+
+/*!
+ * \brief Resize unit to given number.
+ *
+ * \note Newly created dthreads will have no runnable or data, their state
+ * will be ThreadJoined (that means no thread will be physically created
+ * until the next dt_start()).
+ *
+ * \warning Be careful when shrinking unit, joined and idle threads are
+ * reclaimed first, but it may kill your active threads
+ * as a last resort.
+ * Threads will stop at their nearest cancellation point,
+ * so this is potentially an expensive and blocking operation.
+ *
+ * \param unit Unit to be resized.
+ * \param size New unit size.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ENOMEM out of memory error.
+ */
+int dt_resize(dt_unit_t *unit, int size);
+
+/*!
+ * \brief Start all threads in selected unit.
+ *
+ * \param unit Unit to be started.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters (unit is null).
+ */
+int dt_start(dt_unit_t *unit);
+
+/*!
+ * \brief Start given thread.
+ *
+ * \param thread Target thread instance.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int dt_start_id(dthread_t *thread);
+
+/*!
+ * \brief Send given signal to thread.
+ *
+ * \note This is useful to interrupt some blocking I/O as well, for example
+ * with SIGALRM, which is handled by default.
+ * \note Signal handler may be overriden in runnable.
+ *
+ * \param thread Target thread instance.
+ * \param signum Signal code.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int dt_signalize(dthread_t *thread, int signum);
+
+/*!
+ * \brief Wait for all thread in unit to finish.
+ *
+ * \param unit Unit to be joined.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int dt_join(dt_unit_t *unit);
+
+/*!
+ * \brief Stop thread from running.
+ *
+ * Active thread is interrupted at the nearest runnable cancellation point.
+ *
+ * \param thread Target thread instance.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int dt_stop_id(dthread_t *thread);
+
+/*!
+ * \brief Stop all threads in unit.
+ *
+ * Thread is interrupted at the nearest runnable cancellation point.
+ *
+ * \param unit Unit to be stopped.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int dt_stop(dt_unit_t *unit);
+
+/*!
+ * \brief Modify thread priority.
+ *
+ * \param thread Target thread instance.
+ * \param prio Requested priority (positive integer, default is 0).
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int dt_setprio(dthread_t *thread, int prio);
+
+/*!
+ * \brief Set thread to execute another runnable.
+ *
+ * \param thread Target thread instance.
+ * \param runnable Runnable function for target thread.
+ * \param data Data passed to target thread.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ENOTSUP operation not supported.
+ */
+int dt_repurpose(dthread_t *thread, runnable_t runnable, void *data);
+
+/*!
+ * \brief Wake up thread from idle state.
+ *
+ * Thread is awoken from idle state and reenters runnable.
+ * This function only affects idle threads.
+ *
+ * \note Unit needs to be started with dt_start() first, as the function
+ * doesn't affect dead threads.
+ *
+ * \param thread Target thread instance.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ENOTSUP operation not supported.
+ */
+int dt_activate(dthread_t *thread);
+
+/*!
+ * \brief Put thread to idle state, cancells current runnable function.
+ *
+ * Thread is flagged with Cancel flag and returns from runnable at the nearest
+ * cancellation point, which requires complying runnable function.
+ *
+ * \note Thread isn't disposed, but put to idle state until it's requested
+ * again or collected by dt_compact().
+ *
+ * \param thread Target thread instance.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int dt_cancel(dthread_t *thread);
+
+/*!
+ * \brief Collect and dispose idle threads.
+ *
+ * \param unit Target unit instance.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int dt_compact(dt_unit_t *unit);
+
+/*!
+ * \brief Return optimal number of threads for instance.
+ *
+ * It is estimated as NUM_CPUs + 1.
+ * Fallback is DEFAULT_THR_COUNT (\see common.h).
+ *
+ * \return Number of threads.
+ */
+int dt_optimal_size();
+
+/*!
+ * \brief Return true if thread is cancelled.
+ *
+ * Synchronously check for ThreadCancelled flag.
+ *
+ * \param thread Target thread instance.
+ *
+ * \retval 1 if cancelled.
+ * \retval 0 if not cancelled.
+ */
+int dt_is_cancelled(dthread_t *thread);
+
+/*!
+ * \brief Lock unit to prevent parallel operations which could alter unit
+ * at the same time.
+ *
+ * \param unit Target unit instance.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_EAGAIN lack of resources to lock unit, try again.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int dt_unit_lock(dt_unit_t *unit);
+
+/*!
+ * \brief Unlock unit.
+ *
+ * \see dt_unit_lock()
+ *
+ * \param unit Target unit instance.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_EAGAIN lack of resources to unlock unit, try again.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int dt_unit_unlock(dt_unit_t *unit);
+
+#endif // _KNOTD_DTHREADS_H_
+
+/*! @} */
diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c
new file mode 100644
index 0000000..651f0f3
--- /dev/null
+++ b/src/knot/server/journal.c
@@ -0,0 +1,636 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "knot/other/error.h"
+#include "knot/other/debug.h"
+#include "journal.h"
+
+/*! \brief Infinite file size limit. */
+#define FSLIMIT_INF (~((size_t)0))
+
+/*! \brief Node classification macros. */
+#define jnode_flags(j, i) ((j)->nodes[(i)].flags)
+
+/*! \brief Next node. */
+#define jnode_next(j, i) (((i) + 1) % (j)->max_nodes)
+
+/*! \brief Previous node. */
+#define jnode_prev(j, i) (((i) == 0) ? (j)->max_nodes - 1 : (i) - 1)
+
+static inline int sfread(void *dst, size_t len, int fd)
+{
+ return read(fd, dst, len) == len;
+}
+
+static inline int sfwrite(const void *src, size_t len, int fd)
+{
+ return write(fd, src, len) == len;
+}
+
+/*! \brief Equality compare function. */
+static inline int journal_cmp_eq(uint64_t k1, uint64_t k2)
+{
+ if (k1 == k2) {
+ return 0;
+ }
+
+ if (k1 < k2) {
+ return -1;
+ }
+
+ return 1;
+}
+
+/*! \brief Recover metadata from journal. */
+static int journal_recover(journal_t *j)
+{
+ /* Attempt to recover queue. */
+ int qstate[2] = { -1, -1 };
+ unsigned c = 0, p = j->max_nodes - 1;
+ while (1) {
+
+ /* Fetch previous and current node. */
+ journal_node_t *np = j->nodes + p;
+ journal_node_t *nc = j->nodes + c;
+
+ /* Check flags
+ * p c (0 = free, 1 = non-free)
+ * 0 0 - in free segment
+ * 0 1 - c-node is qhead
+ * 1 0 - c-node is qtail
+ * 1 1 - in full segment
+ */
+ unsigned c_set = (nc->flags > JOURNAL_FREE);
+ unsigned p_set = (np->flags > JOURNAL_FREE);
+ if (!p_set && c_set && qstate[0] < 0) {
+ qstate[0] = c; /* Recovered qhead. */
+ dbg_journal_verb("journal: recovered qhead=%u\n",
+ qstate[0]);
+ }
+ if (p_set && !c_set && qstate[1] < 0) {\
+ qstate[1] = c; /* Recovered qtail. */
+ dbg_journal_verb("journal: recovered qtail=%u\n",
+ qstate[1]);
+ }
+
+ /* Both qstates set. */
+ if (qstate[0] > -1 && qstate[1] > -1) {
+ break;
+ }
+
+ /* Set prev and next. */
+ p = c;
+ c = (c + 1) % j->max_nodes;
+
+ /* All nodes probed. */
+ if (c == 0) {
+ dbg_journal("journal: failed to recover node queue\n");
+ break;
+ }
+ }
+
+ /* Evaluate */
+ if (qstate[0] < 0 || qstate[1] < 0) {
+ return KNOTD_ERANGE;
+ }
+
+ /* Write back. */
+ lseek(j->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET);
+ if (!sfwrite(qstate, 2 * sizeof(uint16_t), j->fd)) {
+ dbg_journal("journal: failed to write back queue state\n");
+ return KNOTD_ERROR;
+ }
+
+ /* Reset queue state. */
+ j->qhead = qstate[0];
+ j->qtail = qstate[1];
+ dbg_journal("journal: node queue=<%u,%u> recovered\n",
+ qstate[0], qstate[1]);
+
+
+ return KNOTD_EOK;
+}
+
+int journal_create(const char *fn, uint16_t max_nodes)
+{
+ /* File lock. */
+ struct flock fl;
+ memset(&fl, 0, sizeof(struct flock));
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_pid = getpid();
+
+ /* Create journal file. */
+ int fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG);
+ if (fd < 0) {
+ dbg_journal("journal: failed to create file '%s'\n", fn);
+ return KNOTD_EINVAL;
+ }
+
+ /* Lock. */
+ fcntl(fd, F_SETLKW, &fl);
+ fl.l_type = F_UNLCK;
+
+ /* Create journal header. */
+ dbg_journal("journal: creating header\n");
+ if (!sfwrite(&max_nodes, sizeof(uint16_t), fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ remove(fn);
+ return KNOTD_ERROR;
+ }
+
+ /* Create node queue head + tail.
+ * qhead points to least recent node
+ * qtail points to next free node
+ * qhead == qtail means empty queue
+ */
+ uint16_t zval = 0;
+ if (!sfwrite(&zval, sizeof(uint16_t), fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ remove(fn);
+ return KNOTD_ERROR;
+ }
+
+ if (!sfwrite(&zval, sizeof(uint16_t), fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ remove(fn);
+ return KNOTD_ERROR;
+ }
+
+ dbg_journal_verb("journal: creating free segment descriptor\n");
+
+ /* Create free segment descriptor. */
+ journal_node_t jn;
+ memset(&jn, 0, sizeof(journal_node_t));
+ jn.id = 0;
+ jn.flags = JOURNAL_VALID;
+ jn.pos = JOURNAL_HSIZE + (max_nodes + 1) * sizeof(journal_node_t);
+ jn.len = 0;
+ if (!sfwrite(&jn, sizeof(journal_node_t), fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ remove(fn);
+ return KNOTD_ERROR;
+ }
+
+ /* Create nodes. */
+ dbg_journal("journal: creating node table, size=%u\n", max_nodes);
+ memset(&jn, 0, sizeof(journal_node_t));
+ for(uint16_t i = 0; i < max_nodes; ++i) {
+ if (!sfwrite(&jn, sizeof(journal_node_t), fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ remove(fn);
+ return KNOTD_ERROR;
+ }
+ }
+
+ /* Unlock and close. */
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+
+ /* Journal file created. */
+ dbg_journal("journal: file '%s' initialized\n", fn);
+ return KNOTD_EOK;
+}
+
+journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags)
+{
+ /*! \todo Memory mapping may be faster than stdio? */
+
+ /* File lock. */
+ struct flock fl;
+ memset(&fl, 0, sizeof(struct flock));
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_pid = getpid();
+
+ /* Check file. */
+ struct stat st;
+ if (stat(fn, &st) < 0) {
+ return 0;
+ }
+
+ /* Open journal file for r/w. */
+ int fd = open(fn, O_RDWR);
+ if (fd < 0) {
+ dbg_journal("journal: failed to open file '%s'\n", fn);
+ return 0;
+ }
+
+ /* Attempt to lock. */
+ dbg_journal_verb("journal: locking journal %s\n", fn);
+ int ret = fcntl(fd, F_SETLK, &fl);
+
+ /* Lock. */
+ if (ret < 0) {
+ struct flock efl;
+ memcpy(&efl, &fl, sizeof(struct flock));
+ fcntl(fd, F_GETLK, &efl);
+ log_server_warning("Journal file '%s' is locked by process "
+ "PID=%d, waiting for process to "
+ "release lock.\n",
+ fn, efl.l_pid);
+ ret = fcntl(fd, F_SETLKW, &fl);
+ }
+ fl.l_type = F_UNLCK;
+ dbg_journal("journal: locked journal %s (returned %d)\n", fn, ret);
+
+ /* Read maximum number of entries. */
+ uint16_t max_nodes = 512;
+ if (!sfread(&max_nodes, sizeof(uint16_t), fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ return 0;
+ }
+
+ /* Allocate journal structure. */
+ const size_t node_len = sizeof(journal_node_t);
+ journal_t *j = malloc(sizeof(journal_t) + max_nodes * node_len);
+ if (!j) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ return 0;
+ }
+ j->qhead = j->qtail = 0;
+ j->fd = fd;
+ j->max_nodes = max_nodes;
+ j->bflags = bflags;
+
+ /* Load node queue state. */
+ if (!sfread(&j->qhead, sizeof(uint16_t), fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ free(j);
+ return 0;
+ }
+
+ /* Load queue tail. */
+ if (!sfread(&j->qtail, sizeof(uint16_t), fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ free(j);
+ return 0;
+ }
+
+ /* Load empty segment descriptor. */
+ if (!sfread(&j->free, node_len, fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ free(j);
+ return 0;
+ }
+
+ /* Read journal descriptors table. */
+ if (!sfread(&j->nodes, max_nodes * node_len, fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ free(j);
+ return 0;
+ }
+
+ /* Set file size. */
+ j->fsize = st.st_size;
+ if (fslimit == 0) {
+ j->fslimit = FSLIMIT_INF;
+ } else {
+ j->fslimit = (size_t)fslimit;
+ }
+
+ dbg_journal("journal: opened journal size=%u, queue=<%u, %u>, fd=%d\n",
+ max_nodes, j->qhead, j->qtail, j->fd);
+
+ /* Check node queue. */
+ unsigned qtail_free = (jnode_flags(j, j->qtail) <= JOURNAL_FREE);
+ unsigned qhead_free = j->max_nodes - 1; /* Left of qhead must be free.*/
+ if (j->qhead > 0) {
+ qhead_free = (j->qhead - 1);
+ }
+ qhead_free = (jnode_flags(j, qhead_free) <= JOURNAL_FREE);
+ if ((j->qhead != j->qtail) && (!qtail_free || !qhead_free)) {
+ log_server_warning("Recovering journal '%s' metadata "
+ "after crash.\n",
+ fn);
+ ret = journal_recover(j);
+ if (ret != KNOTD_EOK) {
+ log_server_error("Journal file '%s' is unrecoverable, "
+ "metadata corrupted - %s\n",
+ fn, knotd_strerror(ret));
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ free(j);
+ return 0;
+ }
+ }
+
+ /* Save file lock. */
+ fl.l_type = F_WRLCK;
+ memcpy(&j->fl, &fl, sizeof(struct flock));
+
+ return j;
+}
+
+int journal_fetch(journal_t *journal, uint64_t id,
+ journal_cmp_t cf, journal_node_t** dst)
+{
+ if (journal == 0 || dst == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Check compare function. */
+ if (!cf) {
+ cf = journal_cmp_eq;
+ }
+
+ /*! \todo Organize journal descriptors in btree? */
+ size_t i = jnode_prev(journal, journal->qtail);
+ size_t endp = jnode_prev(journal, journal->qhead);
+ for(; i != endp; i = jnode_prev(journal, i)) {
+ if (cf(journal->nodes[i].id, id) == 0) {
+ *dst = journal->nodes + i;
+ return KNOTD_EOK;
+ }
+ }
+
+ return KNOTD_ENOENT;
+}
+
+int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst)
+{
+ if (journal == 0 || dst == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ journal_node_t *n = 0;
+ if(journal_fetch(journal, id, cf, &n) != 0) {
+ dbg_journal("journal: failed to fetch node with id=%llu\n",
+ (unsigned long long)id);
+ return KNOTD_ENOENT;
+ }
+
+ /* Check valid flag. */
+ if (!(n->flags & JOURNAL_VALID)) {
+ dbg_journal("journal: node with id=%llu is invalid "
+ "(flags=0x%hx)\n", (unsigned long long)id, n->flags);
+ return KNOTD_EINVAL;
+ }
+
+ dbg_journal("journal: reading node with id=%llu, data=<%u, %u>, flags=0x%hx\n",
+ (unsigned long long)id, n->pos, n->pos + n->len, n->flags);
+
+ /* Seek journal node. */
+ lseek(journal->fd, n->pos, SEEK_SET);
+
+ /* Read journal node content. */
+ if (!sfread(dst, n->len, journal->fd)) {
+ return KNOTD_ERROR;
+ }
+
+ return KNOTD_EOK;
+}
+
+int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size)
+{
+ if (journal == 0 || src == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ const size_t node_len = sizeof(journal_node_t);
+
+ /* Find next free node. */
+ uint16_t jnext = (journal->qtail + 1) % journal->max_nodes;
+
+ dbg_journal("journal: will write id=%llu, node=%u, size=%zu, fsize=%zu\n",
+ (unsigned long long)id, journal->qtail, size, journal->fsize);
+
+ /* Calculate remaining bytes to reach file size limit. */
+ size_t fs_remaining = journal->fslimit - journal->fsize;
+
+ /* Increase free segment if on the end of file. */
+ journal_node_t *n = journal->nodes + journal->qtail;
+ if (journal->free.pos + journal->free.len == journal->fsize) {
+
+ dbg_journal_verb("journal: * is last node\n");
+
+ /* Grow journal file until the size limit. */
+ if(journal->free.len < size && size <= fs_remaining) {
+ size_t diff = size - journal->free.len;
+ dbg_journal("journal: * growing by +%zu, pos=%u, "
+ "new fsize=%zu\n",
+ diff, journal->free.pos,
+ journal->fsize + diff);
+ journal->fsize += diff; /* Appending increases file size. */
+ journal->free.len += diff;
+
+ }
+
+ /* Rewind if resize is needed, but the limit is reached. */
+ if(journal->free.len < size && size > fs_remaining) {
+ journal_node_t *head = journal->nodes + journal->qhead;
+ journal->fsize = journal->free.pos;
+ journal->free.pos = head->pos;
+ journal->free.len = 0;
+ dbg_journal_verb("journal: * fslimit reached, "
+ "rewinding to %u\n",
+ head->pos);
+ dbg_journal_verb("journal: * file size trimmed to %zu\n",
+ journal->fsize);
+ }
+ }
+
+ /* Evict occupied nodes if necessary. */
+ while (journal->free.len < size ||
+ journal->nodes[jnext].flags > JOURNAL_FREE) {
+
+ /* Evict least recent node if not empty. */
+ journal_node_t *head = journal->nodes + journal->qhead;
+
+ /* Check if it has been synced to disk. */
+ if (head->flags & JOURNAL_DIRTY) {
+ return KNOTD_EAGAIN;
+ }
+
+ /* Write back evicted node. */
+ head->flags = JOURNAL_FREE;
+ lseek(journal->fd, JOURNAL_HSIZE + (journal->qhead + 1) * node_len, SEEK_SET);
+ if (!sfwrite(head, node_len, journal->fd)) {
+ return KNOTD_ERROR;
+ }
+
+ dbg_journal("journal: * evicted node=%u, growing by +%u\n",
+ journal->qhead, head->len);
+
+ /* Write back query state. */
+ journal->qhead = (journal->qhead + 1) % journal->max_nodes;
+ uint16_t qstate[2] = {journal->qhead, journal->qtail};
+ lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET);
+ if (!sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) {
+ return KNOTD_ERROR;
+ }
+
+ /* Increase free segment. */
+ journal->free.len += head->len;
+ }
+
+ /* Invalidate node and write back. */
+ n->id = id;
+ n->pos = journal->free.pos;
+ n->len = size;
+ n->flags = JOURNAL_FREE;
+ journal_update(journal, n);
+
+ /* Write data to permanent storage. */
+ lseek(journal->fd, n->pos, SEEK_SET);
+ if (!sfwrite(src, size, journal->fd)) {
+ return KNOTD_ERROR;
+ }
+
+ /* Mark node as valid and write back. */
+ n->flags = JOURNAL_VALID | journal->bflags;
+ journal_update(journal, n);
+
+ /* Handle free segment on node rotation. */
+ if (journal->qtail > jnext && journal->fslimit == FSLIMIT_INF) {
+ /* Trim free space. */
+ journal->fsize -= journal->free.len;
+ dbg_journal_verb("journal: * trimmed filesize to %zu\n",
+ journal->fsize);
+
+ /* Rewind free segment. */
+ journal_node_t *n = journal->nodes + jnext;
+ journal->free.pos = n->pos;
+ journal->free.len = 0;
+
+ } else {
+ /* Mark used space. */
+ journal->free.pos += size;
+ journal->free.len -= size;
+ }
+ dbg_journal("journal: finished node=%u, data=<%u, %u> free=<%u, %u>\n",
+ journal->qtail, n->pos, n->pos + n->len,
+ journal->free.pos,
+ journal->free.pos + journal->free.len);
+
+ /* Write back free segment state. */
+ lseek(journal->fd, JOURNAL_HSIZE, SEEK_SET);
+ if (!sfwrite(&journal->free, node_len, journal->fd)) {
+ /* Node is marked valid and failed to shrink free space,
+ * node will be overwritten on the next write. Return error.
+ */
+ dbg_journal("journal: failed to write back "
+ "free segment descriptor\n");
+ return KNOTD_ERROR;
+ }
+
+ /* Node write successful. */
+ journal->qtail = jnext;
+
+ /* Write back queue state, not essential as it may be recovered.
+ * qhead - lowest valid node identifier (least recent)
+ * qtail - highest valid node identifier (most recently used)
+ */
+ uint16_t qstate[2] = {journal->qhead, journal->qtail};
+ lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET);
+ if (!sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) {
+ dbg_journal("journal: failed to write back queue state\n");
+ return KNOTD_ERROR;
+ }
+
+ /*! \todo Delayed write-back? */
+ dbg_journal_verb("journal: write of finished, nqueue=<%u, %u>\n",
+ journal->qhead, journal->qtail);
+
+ return KNOTD_EOK;
+}
+
+int journal_walk(journal_t *journal, journal_apply_t apply)
+{
+ int ret = KNOTD_EOK;
+ size_t i = journal->qhead;
+ for(; i != journal->qtail; i = (i + 1) % journal->max_nodes) {
+ /* Apply function. */
+ ret = apply(journal, journal->nodes + i);
+ }
+
+ return ret;
+}
+
+int journal_update(journal_t *journal, journal_node_t *n)
+{
+ if (!journal || !n) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Calculate node offset. */
+ const size_t node_len = sizeof(journal_node_t);
+ size_t i = n - journal->nodes;
+ if (i > journal->max_nodes) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Calculate node position in permanent storage. */
+ long jn_fpos = JOURNAL_HSIZE + (i + 1) * node_len;
+
+ dbg_journal("journal: syncing journal node=%zu at %ld\n",
+ i, jn_fpos);
+
+ /* Write back. */
+ lseek(journal->fd, jn_fpos, SEEK_SET);
+ if (!sfwrite(n, node_len, journal->fd)) {
+ dbg_journal("journal: failed to writeback node=%llu to %ld\n",
+ (unsigned long long)n->id, jn_fpos);
+ return KNOTD_ERROR;
+ }
+
+ return KNOTD_EOK;
+}
+
+int journal_close(journal_t *journal)
+{
+ /* Check journal. */
+ if (!journal) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Unlock journal file. */
+ journal->fl.l_type = F_UNLCK;
+ fcntl(journal->fd, F_SETLK, &journal->fl);
+ dbg_journal("journal: unlocked journal %p\n", journal);
+
+ /* Close file. */
+ close(journal->fd);
+
+ dbg_journal("journal: closed journal %p\n", journal);
+
+ /* Free allocated resources. */
+ free(journal);
+
+ return KNOTD_EOK;
+}
diff --git a/src/knot/server/journal.h b/src/knot/server/journal.h
new file mode 100644
index 0000000..321b591
--- /dev/null
+++ b/src/knot/server/journal.h
@@ -0,0 +1,243 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file journal.h
+ *
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Journal for storing transactions on permanent storage.
+ *
+ * Journal stores entries on a permanent storage.
+ * Each written entry is guaranteed to persist until
+ * the maximum file size or node count is reached.
+ * Entries are removed from the least recent.
+ *
+ * Journal file structure
+ * <pre>
+ * uint16_t node_count
+ * uint16_t node_queue_head
+ * uint16_t node_queue_tail
+ * journal_entry_t free_segment
+ * node_count *journal_entry_t
+ * ...data...
+ * </pre>
+ * \addtogroup utils
+ * @{
+ */
+
+#ifndef _KNOTD_JOURNAL_H_
+#define _KNOTD_JOURNAL_H_
+
+#include <stdint.h>
+#include <fcntl.h>
+
+/*!
+ * \brief Journal entry flags.
+ */
+typedef enum journal_flag_t {
+ JOURNAL_NULL = 0 << 0, /*!< Invalid journal entry. */
+ JOURNAL_FREE = 1 << 0, /*!< Free journal entry. */
+ JOURNAL_VALID = 1 << 1, /*!< Valid journal entry. */
+ JOURNAL_DIRTY = 1 << 2 /*!< Journal entry cannot be evicted. */
+} journal_flag_t;
+
+/*!
+ * \brief Journal node structure.
+ *
+ * Each node represents journal entry and points
+ * to position of the data in the permanent storage.
+ */
+typedef struct journal_node_t
+{
+ uint64_t id; /*!< Node ID. */
+ uint16_t flags; /*!< Node flags. */
+ uint32_t pos; /*!< Position in journal file. */
+ uint32_t len; /*!< Entry data length. */
+} journal_node_t;
+
+/*!
+ * \brief Journal structure.
+ *
+ * Journal organizes entries as nodes.
+ * Nodes are stored in-memory for fast lookup and also
+ * backed by a permanent storage.
+ * Each journal has a fixed number of nodes.
+ *
+ * \todo Organize nodes in an advanced structure, like
+ * btree or hash table to improve lookup time.
+ */
+typedef struct journal_t
+{
+ int fd;
+ struct flock fl; /*!< File lock. */
+ uint16_t max_nodes; /*!< Number of nodes. */
+ uint16_t qhead; /*!< Node queue head. */
+ uint16_t qtail; /*!< Node queue tail. */
+ uint16_t bflags; /*!< Initial flags for each written node. */
+ size_t fsize; /*!< Journal file size. */
+ size_t fslimit; /*!< File size limit. */
+ journal_node_t free; /*!< Free segment. */
+ journal_node_t nodes[]; /*!< Array of nodes. */
+} journal_t;
+
+/*!
+ * \brief Entry identifier compare function.
+ *
+ * \retval -n if k1 < k2
+ * \retval +n if k1 > k2
+ * \retval 0 if k1 == k2
+ */
+typedef int (*journal_cmp_t)(uint64_t k1, uint64_t k2);
+
+/*!
+ * \brief Function prototype for journal_walk() function.
+ *
+ * \param j Associated journal.
+ * \param n Pointer to target node.
+ */
+typedef int (*journal_apply_t)(journal_t *j, journal_node_t *n);
+
+/*
+ * Journal defaults and constants.
+ */
+#define JOURNAL_NCOUNT 1024 /*!< Default node count. */
+#define JOURNAL_HSIZE (sizeof(uint16_t) * 3) /*!< max_entries, qhead, qtail */
+
+/*!
+ * \brief Create new journal.
+ *
+ * \param fn Journal file name, will be created if not exist.
+ * \param max_nodes Maximum number of nodes in journal.
+ *
+ * \retval KNOTD_EOK if successful.
+ * \retval KNOTD_EINVAL if the file with given name cannot be created.
+ * \retval KNOTD_ERROR on I/O error.
+ */
+int journal_create(const char *fn, uint16_t max_nodes);
+
+/*!
+ * \brief Open journal file for read/write.
+ *
+ * \param fn Journal file name.
+ * \param fslimit File size limit (0 for no limit).
+ * \param bflags Initial flags for each written node.
+ *
+ * \retval new journal instance if successful.
+ * \retval NULL on error.
+ */
+journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags);
+
+/*!
+ * \brief Fetch entry node for given identifier.
+ *
+ * \param journal Associated journal.
+ * \param id Entry identifier.
+ * \param cf Compare function (NULL for equality).
+ * \param dst Destination for journal entry.
+ *
+ * \retval KNOTD_EOK if successful.
+ * \retval KNOTD_ENOENT if not found.
+ */
+int journal_fetch(journal_t *journal, uint64_t id,
+ journal_cmp_t cf, journal_node_t** dst);
+
+/*!
+ * \brief Read journal entry data.
+ *
+ * \param journal Associated journal.
+ * \param id Entry identifier.
+ * \param cf Compare function (NULL for equality).
+ * \param dst Pointer to destination memory.
+ *
+ * \retval KNOTD_EOK if successful.
+ * \retval KNOTD_ENOENT if the entry cannot be found.
+ * \retval KNOTD_EINVAL if the entry is invalid.
+ * \retval KNOTD_ERROR on I/O error.
+ */
+int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst);
+
+/*!
+ * \brief Write journal entry data.
+ *
+ * \param journal Associated journal.
+ * \param id Entry identifier.
+ * \param src Pointer to source data.
+ *
+ * \retval KNOTD_EOK if successful.
+ * \retval KNOTD_EAGAIN if no free node is available, need to remove dirty nodes.
+ * \retval KNOTD_ERROR on I/O error.
+ */
+int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size);
+
+/*!
+ * \brief Return least recent node (journal head).
+ *
+ * \param journal Associated journal.
+ *
+ * \retval node if successful.
+ * \retval NULL if empty.
+ */
+static inline journal_node_t *journal_head(journal_t *journal) {
+ return journal->nodes + journal->qhead;
+}
+
+/*!
+ * \brief Return node after most recent node (journal tail).
+ *
+ * \param journal Associated journal.
+ *
+ * \retval node if successful.
+ * \retval NULL if empty.
+ */
+static inline journal_node_t *journal_end(journal_t *journal) {
+ return journal->nodes + journal->qtail;
+}
+
+/*!
+ * \brief Apply function to each node.
+ *
+ * \param journal Associated journal.
+ * \param apply Function to apply to each node.
+ *
+ * \retval KNOTD_EOK if successful.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int journal_walk(journal_t *journal, journal_apply_t apply);
+
+/*!
+ * \brief Sync node state to permanent storage.
+ *
+ * \note May be used for journal_walk().
+ *
+ * \param journal Associated journal.
+ * \param n Pointer to node (must belong to associated journal).
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int journal_update(journal_t *journal, journal_node_t *n);
+
+/*!
+ * \brief Close journal file.
+ *
+ * \param journal Associated journal.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameter.
+ */
+int journal_close(journal_t *journal);
+
+#endif /* _KNOTD_JOURNAL_H_ */
diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c
new file mode 100644
index 0000000..3966b26
--- /dev/null
+++ b/src/knot/server/notify.c
@@ -0,0 +1,327 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "knot/server/notify.h"
+
+#include "libknot/dname.h"
+#include "libknot/packet/packet.h"
+#include "libknot/rrset.h"
+#include "libknot/packet/response.h"
+#include "libknot/packet/query.h"
+#include "libknot/consts.h"
+#include "knot/other/error.h"
+#include "libknot/zone/zonedb.h"
+#include "libknot/common.h"
+#include "libknot/util/error.h"
+#include "libknot/util/wire.h"
+#include "knot/server/zones.h"
+#include "common/acl.h"
+#include "common/evsched.h"
+#include "knot/other/debug.h"
+#include "knot/server/server.h"
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+
+static int notify_request(const knot_rrset_t *rrset,
+ uint8_t *buffer, size_t *size)
+{
+ knot_packet_t *pkt = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ CHECK_ALLOC_LOG(pkt, KNOTD_ENOMEM);
+
+ /*! \todo Get rid of the numeric constant. */
+ int rc = knot_packet_set_max_size(pkt, 512);
+ if (rc != KNOT_EOK) {
+ knot_packet_free(&pkt);
+ return KNOTD_ERROR;
+ }
+
+ rc = knot_query_init(pkt);
+ if (rc != KNOT_EOK) {
+ knot_packet_free(&pkt);
+ return KNOTD_ERROR;
+ }
+
+ knot_question_t question;
+
+ // this is ugly!!
+ question.qname = rrset->owner;
+ question.qtype = rrset->type;
+ question.qclass = rrset->rclass;
+
+ rc = knot_query_set_question(pkt, &question);
+ if (rc != KNOT_EOK) {
+ knot_packet_free(&pkt);
+ return KNOTD_ERROR;
+ }
+
+ /* Set random query ID. */
+ knot_packet_set_random_id(pkt);
+ knot_wire_set_id(pkt->wireformat, pkt->header.id);
+
+ /*! \todo add the SOA RR to the Answer section as a hint */
+ /*! \todo this should not use response API!! */
+// rc = knot_response_add_rrset_answer(pkt, rrset, 0, 0, 0);
+// if (rc != KNOT_EOK) {
+// knot_packet_free(&pkt);
+// return rc;
+// }
+
+ /*! \todo this should not use response API!! */
+ knot_response_set_aa(pkt);
+
+ knot_query_set_opcode(pkt, KNOT_OPCODE_NOTIFY);
+
+ /*! \todo OPT RR ?? */
+
+ uint8_t *wire = NULL;
+ size_t wire_size = 0;
+ rc = knot_packet_to_wire(pkt, &wire, &wire_size);
+ if (rc != KNOT_EOK) {
+ knot_packet_free(&pkt);
+ return KNOTD_ERROR;
+ }
+
+ if (wire_size > *size) {
+ knot_packet_free(&pkt);
+ return KNOTD_ESPACE;
+ }
+
+ memcpy(buffer, wire, wire_size);
+ *size = wire_size;
+
+ knot_packet_dump(pkt);
+
+ knot_packet_free(&pkt);
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int notify_create_response(knot_packet_t *request, uint8_t *buffer,
+ size_t *size)
+{
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ CHECK_ALLOC_LOG(response, KNOTD_ENOMEM);
+
+ /* Set maximum packet size. */
+ knot_packet_set_max_size(response, *size);
+ knot_response_init_from_query(response, request);
+
+ // TODO: copy the SOA in Answer section
+ uint8_t *wire = NULL;
+ size_t wire_size = 0;
+ int rc = knot_packet_to_wire(response, &wire, &wire_size);
+ if (rc != KNOT_EOK) {
+ knot_packet_free(&response);
+ return rc;
+ }
+
+ if (wire_size > *size) {
+ knot_packet_free(&response);
+ return KNOTD_ESPACE;
+ }
+
+ memcpy(buffer, wire, wire_size);
+ *size = wire_size;
+
+ knot_packet_dump(response);
+ knot_packet_free(&response);
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+int notify_create_request(const knot_zone_contents_t *zone, uint8_t *buffer,
+ size_t *size)
+{
+ const knot_rrset_t *soa_rrset = knot_node_rrset(
+ knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
+ if (soa_rrset == NULL) {
+ return KNOTD_ERROR;
+ }
+
+ return notify_request(soa_rrset, buffer, size);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int notify_check_and_schedule(knot_nameserver_t *nameserver,
+ const knot_zone_t *zone,
+ sockaddr_t *from)
+{
+ if (zone == NULL || from == NULL || knot_zone_data(zone) == NULL) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Check ACL for notify-in. */
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ if (from) {
+ if (acl_match(zd->notify_in, from) == ACL_DENY) {
+ /* rfc1996: Ignore request and report incident. */
+ char straddr[SOCKADDR_STRLEN];
+ sockaddr_tostr(from, straddr, sizeof(straddr));
+ log_zone_notice("Unauthorized NOTIFY query "
+ "from %s:%d to zone '%s'.\n",
+ straddr, sockaddr_portnum(from),
+ zd->conf->name);
+ return KNOT_ERROR;
+ } else {
+ dbg_notify("notify: authorized NOTIFY query.\n");
+ }
+ }
+
+ /*! \todo Packet may contain updated RRs. */
+
+ /* Cancel REFRESH/RETRY timer. */
+ evsched_t *sched = ((server_t *)knot_ns_get_data(nameserver))->sched;
+ event_t *refresh_ev = zd->xfr_in.timer;
+ if (refresh_ev) {
+ dbg_notify("notify: expiring REFRESH timer\n");
+ evsched_cancel(sched, refresh_ev);
+
+ /* Set REFRESH timer for now. */
+ evsched_schedule(sched, refresh_ev, 0);
+ }
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int notify_process_request(knot_nameserver_t *ns,
+ knot_packet_t *notify,
+ sockaddr_t *from,
+ uint8_t *buffer, size_t *size)
+{
+ /*! \todo Most of this function is identical to xfrin_transfer_needed()
+ * - it will be fine to merge the code somehow.
+ */
+
+ if (notify == NULL || ns == NULL || buffer == NULL
+ || size == NULL || from == NULL) {
+ dbg_notify("notify: invalid parameters for %s()\n",
+ "notify_process_request");
+ return KNOTD_EINVAL;
+ }
+
+ int ret = KNOTD_EOK;
+
+ dbg_notify("notify: parsing rest of the packet\n");
+ if (notify->parsed < notify->size) {
+ ret = knot_packet_parse_rest(notify);
+ if (ret != KNOT_EOK) {
+ dbg_notify("notify: failed to parse NOTIFY query\n");
+ knot_ns_error_response(ns, knot_packet_id(notify),
+ KNOT_RCODE_FORMERR, buffer,
+ size);
+ return KNOTD_EOK;
+ }
+ }
+
+ // create NOTIFY response
+ dbg_notify("notify: creating response\n");
+ ret = notify_create_response(notify, buffer, size);
+ if (ret != KNOTD_EOK) {
+ dbg_notify("notify: failed to create NOTIFY response\n");
+ knot_ns_error_response(ns, knot_packet_id(notify),
+ KNOT_RCODE_SERVFAIL, buffer,
+ size);
+ return KNOTD_EOK;
+ }
+
+ // find the zone
+ const knot_dname_t *qname = knot_packet_qname(notify);
+ const knot_zone_t *z = knot_zonedb_find_zone_for_name(
+ ns->zone_db, qname);
+ if (z == NULL) {
+ dbg_notify("notify: failed to find zone by name\n");
+ knot_ns_error_response(ns, knot_packet_id(notify),
+ KNOT_RCODE_REFUSED, buffer,
+ size);
+ return KNOTD_EOK;
+ }
+
+ notify_check_and_schedule(ns, z, from);
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int notify_process_response(knot_nameserver_t *nameserver,
+ knot_packet_t *notify,
+ sockaddr_t *from,
+ uint8_t *buffer, size_t *size)
+{
+ if (nameserver == NULL || notify == NULL || from == NULL
+ || buffer == NULL || size == NULL) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Assert no response size. */
+ *size = 0;
+
+ /* Find matching zone. */
+ const knot_dname_t *zone_name = knot_packet_qname(notify);
+ knot_zone_t *zone = knot_zonedb_find_zone(nameserver->zone_db,
+ zone_name);
+ if (!zone) {
+ return KNOTD_ENOENT;
+ }
+ if (!knot_zone_data(zone)) {
+ return KNOTD_ENOENT;
+ }
+
+ /* Match ID against awaited. */
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ pthread_mutex_lock(&zd->lock);
+ uint16_t pkt_id = knot_packet_id(notify);
+ notify_ev_t *ev = 0, *match = 0;
+ WALK_LIST(ev, zd->notify_pending) {
+ if ((int)pkt_id == ev->msgid) {
+ match = ev;
+ break;
+ }
+ }
+
+ /* Found waiting NOTIFY query? */
+ if (!match) {
+ log_server_notice("No pending NOTIFY query found for ID=%u\n",
+ pkt_id);
+ return KNOTD_ERROR;
+ }
+
+ /* NOTIFY is now finished. */
+ zones_cancel_notify(zd, match);
+
+ /* Zone was removed/reloaded. */
+ pthread_mutex_unlock(&zd->lock);
+
+ log_server_info("Received response for pending NOTIFY query ID=%u\n",
+ pkt_id);
+
+ return KNOTD_EOK;
+}
+
diff --git a/src/knot/server/notify.h b/src/knot/server/notify.h
new file mode 100644
index 0000000..c1bebb8
--- /dev/null
+++ b/src/knot/server/notify.h
@@ -0,0 +1,128 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file notify.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief NOTIFY request/reply API.
+ *
+ * \addtogroup query_processing
+ * @{
+ */
+
+#ifndef _KNOTD_NOTIFY_H_
+#define _KNOTD_NOTIFY_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "libknot/zone/zone.h"
+#include "libknot/packet/packet.h"
+#include "libknot/zone/zonedb.h"
+#include "common/lists.h"
+#include "common/sockaddr.h"
+#include "libknot/nameserver/name-server.h"
+
+/*!
+ * \brief Pending NOTIFY event.
+ * \see knot_zone_t.notify_pending
+ */
+typedef struct notify_ev_t {
+ node n;
+ int timeout; /*!< Timeout for events. */
+ int retries; /*!< Number of retries. */
+ int msgid; /*!< ID of pending NOTIFY. */
+ sockaddr_t addr; /*!< Slave server address. */
+ struct event_t *timer; /*!< Event timer. */
+ knot_zone_t *zone; /*!< Associated zone. */
+} notify_ev_t;
+
+/*!
+ * \brief Creates a NOTIFY request message for SOA RR of the given zone.
+ *
+ * \param zone Zone from which to take the SOA RR.
+ * \param buffer Buffer to fill the message in.
+ * \param size In: available space in the buffer. Out: actual size of the
+ * message in bytes.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_ESPACE
+ * \retval KNOTD_ERROR
+ */
+int notify_create_request(const knot_zone_contents_t *zone, uint8_t *buffer,
+ size_t *size);
+
+/*!
+ * \brief Creates a response for NOTIFY query.
+ *
+ * Valid NOTIFY query expires REFRESH timer for received qname.
+ *
+ * \see RFC1996 for query and response format.
+ *
+ * \param nameserver Name server structure to provide the needed data.
+ * \param query Response structure with parsed query.
+ * \param response_wire Place for the response in wire format.
+ * \param rsize Input: maximum acceptable size of the response. Output: real
+ * size of the response.
+ *
+ * \retval KNOTD_EOK if a valid response was created.
+ * \retval KNOTD_EACCES sender is not authorized to request NOTIFY.
+ * \retval KNOTD_EMALF if an error occured and the response is not valid.
+ */
+/*!
+ * \brief Evaluates incoming NOTIFY request and produces a reply.
+ *
+ * \param notify (Partially) parsed packet with the NOTIFY request.
+ * \param zonedb Zone database of the server.
+ * \param zone Zone which is probably out-of-date or NULL if there either is no
+ * zone corresponding to the request or if the zone is up-to-date.
+ * \param buffer Buffer to fill the message in.
+ * \param size In: available space in the buffer. Out: actual size of the
+ * response message in bytes.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_EINVAL
+ * \retval KNOTD_EMALF
+ * \retval KNOTD_ERROR
+ */
+int notify_process_request(knot_nameserver_t *nameserver,
+ knot_packet_t *notify,
+ sockaddr_t *from,
+ uint8_t *buffer, size_t *size);
+
+/*!
+ * \brief Processes NOTIFY response packet.
+ *
+ * \param nameserver Name server structure to provide the needed data.
+ * \param from Address of the response sender.
+ * \param packet Parsed response packet.
+ * \param response_wire Place for the response in wire format.
+ * \param rsize Input: maximum acceptable size of the response. Output: real
+ * size of the response.
+ *
+ * \retval KNOTD_EOK if a valid response was created.
+ * \retval KNOTD_EINVAL on invalid parameters or packet.
+ * \retval KNOTD_EMALF if an error occured and the response is not valid.
+ */
+int notify_process_response(knot_nameserver_t *nameserver,
+ knot_packet_t *notify,
+ sockaddr_t *from,
+ uint8_t *buffer, size_t *size);
+
+#endif /* _KNOTD_NOTIFY_H_ */
+
+/*! @} */
diff --git a/src/knot/server/server.c b/src/knot/server/server.c
new file mode 100644
index 0000000..80db35d
--- /dev/null
+++ b/src/knot/server/server.c
@@ -0,0 +1,730 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <openssl/evp.h>
+#include <assert.h>
+
+#include "knot/common.h"
+#include "knot/other/error.h"
+#include "knot/server/server.h"
+#include "knot/server/udp-handler.h"
+#include "knot/server/tcp-handler.h"
+#include "knot/server/xfr-handler.h"
+#include "libknot/nameserver/name-server.h"
+#include "knot/stat/stat.h"
+#include "libknot/zone/zonedb.h"
+#include "knot/zone/zone-load.h"
+#include "libknot/dname.h"
+#include "knot/conf/conf.h"
+#include "knot/server/zones.h"
+
+/*! \brief Event scheduler loop. */
+static int evsched_run(dthread_t *thread)
+{
+ iohandler_t *sched_h = (iohandler_t *)thread->data;
+ evsched_t *s = (evsched_t*)sched_h->data;
+ if (!s) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Run event loop. */
+ event_t *ev = 0;
+ while((ev = evsched_next(s))) {
+
+ /* Error. */
+ if (!ev) {
+ return KNOTD_ERROR;
+ }
+
+ /* Process termination event. */
+ if (ev->type == EVSCHED_TERM) {
+ evsched_event_finished(s);
+ evsched_event_free(s, ev);
+ break;
+ }
+
+ /* Process event. */
+ if (ev->type == EVSCHED_CB && ev->cb) {
+ ev->cb(ev);
+ evsched_event_finished(s);
+ } else {
+ evsched_event_finished(s);
+ evsched_event_free(s, ev);
+ }
+
+ /* Check for thread cancellation. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+ }
+
+ return KNOTD_EOK;
+}
+
+/*! \brief List item for generic pointers. */
+typedef struct pnode_t {
+ struct node *next, *prev; /* Keep the ordering for lib/lists.h */
+ void *p; /*!< \brief Useful data pointer. */
+} pnode_t;
+
+/*! \brief Unbind and dispose given interface. */
+static void server_remove_iface(iface_t *iface)
+{
+ /* Free UDP handler. */
+ iohandler_t *handler = iface->handler[UDP_ID];
+ if (handler) {
+ server_remove_handler(handler->server, handler);
+ } else {
+ if (iface->fd[UDP_ID] > -1) {
+ close(iface->fd[UDP_ID]);
+ }
+ }
+
+ /* Free TCP handler. */
+ handler = iface->handler[TCP_ID];
+ if (handler) {
+ server_remove_handler(handler->server, handler);
+ } else {
+ if (iface->fd[TCP_ID] > -1) {
+ close(iface->fd[TCP_ID]);
+ }
+ }
+
+ /* Free interface. */
+ free(iface->addr);
+ free(iface);
+}
+
+/*!
+ * \brief Initialize new interface from config value.
+ *
+ * Both TCP and UDP sockets will be created for the interface.
+ *
+ * \param new_if Allocated memory for the interface.
+ * \param cfg_if Interface template from config.
+ *
+ * \retval 0 if successful (EOK).
+ * \retval <0 on errors (EACCES, EINVAL, ENOMEM, EADDRINUSE).
+ */
+static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if)
+{
+ /* Initialize interface. */
+ char errbuf[128];
+ int opt = 1024 * 1024;
+ int snd_opt = 1024 * 1024;
+ memset(new_if, 0, sizeof(iface_t));
+
+ /* Create UDP socket. */
+ int sock = socket_create(cfg_if->family, SOCK_DGRAM);
+ if (sock <= 0) {
+ strerror_r(errno, errbuf, sizeof(errbuf));
+ log_server_error("Could not create UDP socket: %s.\n",
+ errbuf);
+ return sock;
+ }
+ if (socket_bind(sock, cfg_if->family,
+ cfg_if->address, cfg_if->port) < 0) {
+ socket_close(sock);
+ log_server_error("Could not bind to "
+ "UDP interface %s port %d.\n",
+ cfg_if->address, cfg_if->port);
+ return knot_map_errno(EACCES, EINVAL, ENOMEM);
+ }
+
+ new_if->fd[UDP_ID] = sock;
+ new_if->type[UDP_ID] = cfg_if->family;
+
+ /* Set socket options - voluntary. */
+ if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_opt, sizeof(snd_opt)) < 0) {
+ // log_server_warning("Failed to configure socket "
+ // "write buffers.\n");
+ }
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
+ // log_server_warning("Failed to configure socket read buffers.\n");
+ }
+
+ /* Create TCP socket. */
+ int ret = 0;
+ sock = socket_create(cfg_if->family, SOCK_STREAM);
+ if (sock <= 0) {
+ socket_close(new_if->fd[UDP_ID]);
+ strerror_r(errno, errbuf, sizeof(errbuf));
+ log_server_error("Could not create TCP socket: %s.\n",
+ errbuf);
+ return sock;
+ }
+
+ ret = socket_bind(sock, cfg_if->family, cfg_if->address, cfg_if->port);
+ if (ret < 0) {
+ socket_close(new_if->fd[UDP_ID]);
+ socket_close(sock);
+ log_server_error("Could not bind to "
+ "TCP interface %s port %d.\n",
+ cfg_if->address, cfg_if->port);
+ return ret;
+ }
+
+ ret = socket_listen(sock, TCP_BACKLOG_SIZE);
+ if (ret < 0) {
+ socket_close(new_if->fd[UDP_ID]);
+ socket_close(sock);
+ log_server_error("Failed to listen on "
+ "TCP interface %s port %d.\n",
+ cfg_if->address, cfg_if->port);
+ return ret;
+ }
+
+ new_if->fd[TCP_ID] = sock;
+ new_if->type[TCP_ID] = cfg_if->family;
+ new_if->port = cfg_if->port;
+ new_if->addr = strdup(cfg_if->address);
+ return KNOTD_EOK;
+}
+
+/*!
+ * \brief Update bound sockets according to configuration.
+ *
+ * \param server Server instance.
+ * \return number of added sockets.
+ */
+static int server_bind_sockets(server_t *server)
+{
+ /*! \todo This requires locking to disable parallel updates. */
+
+ /* Lock configuration. */
+ conf_read_lock();
+
+ /* Prepare helper lists. */
+ int bound = 0;
+ node *m = 0;
+ list *newlist, unmatched;
+ newlist = malloc(sizeof(list));
+ init_list(newlist);
+ init_list(&unmatched);
+
+ /* Duplicate current list. */
+ /*! \note Pointers to addr, handlers etc. will be shared. */
+ list_dup(&unmatched, server->ifaces, sizeof(iface_t));
+
+ /* Update pointers. */
+ WALK_LIST(m, unmatched) {
+
+ /* Interfaces. */
+ iface_t *m_if = (iface_t*)m;
+ for (int i = 0; i <= TCP_ID; ++i) {
+ iohandler_t *h = m_if->handler[i];
+ if (h) {
+ h->iface = m_if;
+ }
+
+ }
+ }
+
+ /* Update bound interfaces. */
+ node *n = 0;
+ WALK_LIST(n, conf()->ifaces) {
+
+ /* Find already matching interface. */
+ int found_match = 0;
+ conf_iface_t *cfg_if = (conf_iface_t*)n;
+ WALK_LIST(m, unmatched) {
+ iface_t *srv_if = (iface_t*)m;
+
+ /* Matching port and address. */
+ if (cfg_if->port == srv_if->port) {
+ if (strcmp(cfg_if->address, srv_if->addr) == 0) {
+ found_match = 1;
+ break;
+ }
+ }
+ }
+
+ /* Found already bound interface. */
+ if (found_match) {
+ rem_node(m);
+ } else {
+
+ /* Create new interface. */
+ m = malloc(sizeof(iface_t));
+ if (server_init_iface((iface_t*)m, cfg_if) < 0) {
+ free(m);
+ m = 0;
+ }
+
+ log_server_info("Binding to interface %s port %d.\n",
+ cfg_if->address, cfg_if->port);
+ }
+
+ /* Move to new list. */
+ if (m) {
+ add_tail(newlist, m);
+ ++bound;
+ }
+ }
+
+ /* Unlock configuration. */
+ conf_read_unlock();
+
+ /* Publish new list. */
+ list* oldlist = rcu_xchg_pointer(&server->ifaces, newlist);
+
+ /* Ensure no one is reading old interfaces. */
+ synchronize_rcu();
+
+ /* Remove deprecated interfaces. */
+ WALK_LIST_DELSAFE(n, m, unmatched) {
+ iface_t *rm_if = (iface_t*)n;
+ log_server_info("Removing interface %s port %d.\n",
+ rm_if->addr, rm_if->port);
+ server_remove_iface(rm_if);
+ }
+
+ /* Free original list. */
+ WALK_LIST_DELSAFE(n, m, *oldlist) {
+ /*! \note Need to keep internal pointers, as they are shared
+ * with the newly published list. */
+ free(n);
+ }
+ free(oldlist);
+
+ return bound;
+}
+
+/*!
+ * \brief Update socket handlers according to configuration.
+ *
+ * \param server Server instance.
+ * \retval 0 if successful (EOK).
+ * \retval <0 on errors (EINVAL).
+ */
+static int server_bind_handlers(server_t *server)
+{
+ if (!server || !server->ifaces) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Lock config. */
+ conf_read_lock();
+
+ /* Estimate number of threads/manager. */
+ int thr_count = 0;
+ int tcp_unit_size = 0;
+ if (conf()->workers < 1) {
+ thr_count = dt_optimal_size();
+ tcp_unit_size = (thr_count * 2) + 1; /* Will be always odd. */
+ } else {
+ thr_count = conf()->workers;
+ tcp_unit_size = thr_count + 1; /* Force configured value. */
+ }
+
+ dbg_server("server: configured %d worker%s per UDP iface\n",
+ thr_count, thr_count > 1 ? "s" : "");
+ dbg_server("server: configured %d worker%s per TCP iface\n",
+ tcp_unit_size - 1, (tcp_unit_size - 1) > 1 ? "s" : "");
+
+ /* Create socket handlers. */
+ node *n = 0;
+ iohandler_t* h = 0;
+ WALK_LIST(n, *server->ifaces) {
+
+ iface_t *iface = (iface_t*)n;
+
+ /* Create UDP handlers. */
+ dt_unit_t *unit = 0;
+ if (!iface->handler[UDP_ID]) {
+ unit = dt_create_coherent(thr_count, &udp_master, 0);
+ h = server_create_handler(server, iface->fd[UDP_ID], unit);
+ h->type = iface->type[UDP_ID];
+ h->iface = iface;
+
+ /* Save pointer. */
+ rcu_set_pointer(&iface->handler[UDP_ID], h);
+ dbg_server("server: creating UDP socket handlers for '%s:%d'\n",
+ iface->addr, iface->port);
+
+ }
+
+ /* Create TCP handlers. */
+ if (!iface->handler[TCP_ID]) {
+ unit = dt_create(tcp_unit_size);
+ h = server_create_handler(server, iface->fd[TCP_ID], unit);
+ tcp_loop_unit(h, unit);
+ h->type = iface->type[TCP_ID];
+ h->iface = iface;
+
+ /* Save pointer. */
+ rcu_set_pointer(&iface->handler[TCP_ID], h);
+ dbg_server("server: creating TCP socket handlers for '%s:%d'\n",
+ iface->addr, iface->port);
+ }
+
+ }
+
+ /* Unlock config. */
+ conf_read_unlock();
+
+ return KNOTD_EOK;
+}
+
+server_t *server_create()
+{
+ // Create server structure
+ server_t *server = malloc(sizeof(server_t));
+ if (server == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ server->state = ServerIdle;
+ init_list(&server->handlers);
+ server->ifaces = malloc(sizeof(list));
+ init_list(server->ifaces);
+
+ // Create event scheduler
+ dbg_server("server: creating event scheduler\n");
+ server->sched = evsched_new();
+ dt_unit_t *unit = dt_create_coherent(1, evsched_run, 0);
+ iohandler_t *h = server_create_handler(server, -1, unit);
+ h->data = server->sched;
+
+ // Create name server
+ dbg_server("server: creating Name Server structure\n");
+ server->nameserver = knot_ns_create();
+ if (server->nameserver == NULL) {
+ free(server);
+ return NULL;
+ }
+ knot_ns_set_data(server->nameserver, server);
+ dbg_server("server: initializing OpenSSL\n");
+ OpenSSL_add_all_digests();
+
+ // Create XFR handler
+ server->xfr_h = xfr_create(XFR_THREADS_COUNT, server->nameserver);
+ if (!server->xfr_h) {
+ knot_ns_destroy(&server->nameserver);
+ free(server);
+ return NULL;
+ }
+
+ dbg_server("server: created server instance\n");
+ return server;
+}
+
+iohandler_t *server_create_handler(server_t *server, int fd, dt_unit_t *unit)
+{
+ // Create new worker
+ iohandler_t *handler = malloc(sizeof(iohandler_t));
+ if (handler == 0) {
+ ERR_ALLOC_FAILED;
+ return 0;
+ }
+
+ // Initialize
+ handler->fd = fd;
+ handler->type = 0;
+ handler->state = ServerIdle;
+ handler->server = server;
+ handler->unit = unit;
+ handler->iface = 0;
+ handler->data = 0;
+ handler->interrupt = 0;
+
+ // Update unit data object
+ for (int i = 0; i < unit->size; ++i) {
+ dthread_t *thread = unit->threads[i];
+ if (thread->run) {
+ dt_repurpose(thread, thread->run, handler);
+ }
+ }
+
+ /*! \todo This requires either RCU compatible ptr swap or locking. */
+
+ /* Lock RCU. */
+ rcu_read_lock();
+
+ // Update list
+ add_tail(&server->handlers, (node*)handler);
+
+ /* Unlock RCU. */
+ rcu_read_unlock();
+
+ return handler;
+}
+
+int server_remove_handler(server_t *server, iohandler_t *h)
+{
+ // Check
+ if (h == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Lock RCU. */
+ rcu_read_lock();
+
+ /*! \todo This requires either RCU compatible ptr swap or locking. */
+
+ // Remove node
+ rem_node((node*)h);
+
+ // Wait for dispatcher to finish
+ if (h->state & ServerRunning) {
+ h->state = ServerIdle;
+ dt_stop(h->unit);
+
+ /* Call interrupt handler. */
+ if (h->interrupt) {
+ h->interrupt(h);
+ }
+
+ dt_join(h->unit);
+ }
+
+ // Close socket
+ if (h->fd >= 0) {
+ socket_close(h->fd);
+ h->fd = -1;
+ }
+
+ // Update interface
+ if (h->iface) {
+ int id = UDP_ID;
+ if (h->iface->handler[TCP_ID] == h) {
+ id = TCP_ID;
+ }
+
+ h->iface->fd[id] = h->fd;
+ h->iface->handler[id] = 0;
+ }
+
+ /* Unlock RCU. */
+ rcu_read_unlock();
+
+ /* RCU synchronize. */
+ synchronize_rcu();
+
+ // Destroy dispatcher and worker
+ dt_delete(&h->unit);
+ free(h);
+ return KNOTD_EOK;
+}
+
+int server_start(server_t *server)
+{
+ // Check server
+ if (server == 0) {
+ return KNOTD_EINVAL;
+ }
+
+ dbg_server("server: starting server instance\n");
+
+ /* Start XFR handler. */
+ xfr_start(server->xfr_h);
+
+ /* Lock configuration. */
+ conf_read_lock();
+
+ // Start dispatchers
+ int ret = KNOTD_EOK;
+ server->state |= ServerRunning;
+ iohandler_t *h = 0;
+ WALK_LIST(h, server->handlers) {
+
+ /* Already running. */
+ if (h->state & ServerRunning) {
+ continue;
+ }
+
+ h->state = ServerRunning;
+ ret = dt_start(h->unit);
+ if (ret < 0) {
+ break;
+ }
+ }
+
+ /* Unlock configuration. */
+ conf_read_unlock();
+
+ dbg_server("server: server started\n");
+
+ return ret;
+}
+
+int server_wait(server_t *server)
+{
+ /* Join threading unit. */
+ xfr_join(server->xfr_h);
+
+ /* Lock RCU. */
+ rcu_read_lock();
+
+ // Wait for handlers to finish
+ int ret = 0;
+ iohandler_t *h = 0, *nxt = 0;
+ WALK_LIST_DELSAFE(h, nxt, server->handlers) {
+
+ /* Unlock RCU. */
+ rcu_read_unlock();
+
+ /* Remove handler. */
+ int dret = dt_join(h->unit);
+ if (dret < 0) {
+ ret = dret;
+ }
+ server_remove_handler(server, h);
+
+ /* Relock RCU. */
+ rcu_read_lock();
+ }
+
+ /* Unlock RCU. */
+ rcu_read_unlock();
+
+ return ret;
+}
+
+void server_stop(server_t *server)
+{
+ dbg_server("server: stopping server\n");
+
+ /* Wait for XFR master. */
+ xfr_stop(server->xfr_h);
+
+ /* Interrupt XFR handler execution. */
+ if (server->xfr_h->interrupt) {
+ server->xfr_h->interrupt(server->xfr_h);
+ }
+
+ /* Send termination event. */
+ evsched_schedule_term(server->sched, 0);
+
+ /* Lock RCU. */
+ rcu_read_lock();
+
+ /* Notify servers to stop. */
+ log_server_info("Stopping server...\n");
+ server->state &= ~ServerRunning;
+ iohandler_t *h = 0;
+ WALK_LIST(h, server->handlers) {
+ h->state = ServerIdle;
+ dt_stop(h->unit);
+
+ /* Call interrupt handler. */
+ if (h->interrupt) {
+ h->interrupt(h);
+ }
+ }
+
+ /* Unlock RCU. */
+ rcu_read_unlock();
+}
+
+void server_destroy(server_t **server)
+{
+ // Check server
+ if (!server) {
+ return;
+ }
+ if (!*server) {
+ return;
+ }
+
+ dbg_server("server: destroying server instance\n");
+
+ // Free XFR master
+ xfr_free((*server)->xfr_h);
+
+ // Free interfaces
+ node *n = 0, *nxt = 0;
+ if ((*server)->ifaces) {
+ WALK_LIST_DELSAFE(n, nxt, *(*server)->ifaces) {
+ iface_t *iface = (iface_t*)n;
+ server_remove_iface(iface);
+ }
+ free((*server)->ifaces);
+ }
+
+ stat_static_gath_free();
+ knot_ns_destroy(&(*server)->nameserver);
+
+ // Delete event scheduler
+ evsched_delete(&(*server)->sched);
+
+ free(*server);
+
+ EVP_cleanup();
+
+ *server = NULL;
+}
+
+int server_conf_hook(const struct conf_t *conf, void *data)
+{
+ server_t *server = (server_t *)data;
+
+ if (!server) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Update bound sockets. */
+ int ret = KNOTD_EOK;
+ if ((ret = server_bind_sockets(server)) < 0) {
+ log_server_error("Failed to bind configured "
+ "interfaces.\n");
+ return KNOTD_ERROR;
+ }
+
+ /* Update handlers. */
+ if ((ret = server_bind_handlers(server)) < 0) {
+ log_server_error("Failed to create handlers for "
+ "configured interfaces.\n");
+ return ret;
+ }
+
+ /* Exit if the server is not running. */
+ if (!(server->state & ServerRunning)) {
+ return KNOTD_ENOTRUNNING;
+ }
+
+ /* Lock configuration. */
+ conf_read_lock();
+
+ /* Start new handlers. */
+ iohandler_t *h = 0;
+ WALK_LIST(h, server->handlers) {
+ if (!(h->state & ServerRunning)) {
+ h->state = ServerRunning;
+ ret = dt_start(h->unit);
+ if (ret < 0) {
+ log_server_error("Handler for %s:%d "
+ "has failed to start.\n",
+ h->iface->addr,
+ h->iface->port);
+ break;
+ }
+ }
+ }
+
+ /* Unlock config. */
+ conf_read_unlock();
+
+ return ret;
+}
+
diff --git a/src/knot/server/server.h b/src/knot/server/server.h
new file mode 100644
index 0000000..480219b
--- /dev/null
+++ b/src/knot/server/server.h
@@ -0,0 +1,211 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file server.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Core server functions.
+ *
+ * Contains the main high-level server structure (server_t) and interface
+ * to functions taking care of proper initialization of the server and clean-up
+ * when terminated.
+ *
+ * As of now, the server supports only one zone file and only in a special
+ * format.
+ *
+ * \see zone-parser.h
+ *
+ * \addtogroup server
+ * @{
+ */
+
+#ifndef _KNOTD_SERVER_H_
+#define _KNOTD_SERVER_H_
+
+#include "knot/common.h"
+#include "libknot/nameserver/name-server.h"
+#include "knot/server/xfr-handler.h"
+#include "knot/server/socket.h"
+#include "knot/server/dthreads.h"
+#include "libknot/zone/zonedb.h"
+#include "common/evsched.h"
+#include "common/lists.h"
+
+/* Forwad declarations. */
+struct iface_t;
+struct iohandler_t;
+struct server_t;
+struct conf_t;
+
+/*! \brief I/O handler structure.
+ */
+typedef struct iohandler_t {
+ struct node *next, *prev;
+ int fd; /*!< I/O filedescriptor */
+ int type; /*!< Descriptor type/family. */
+ unsigned state; /*!< Handler state */
+ dt_unit_t *unit; /*!< Threading unit */
+ struct iface_t *iface; /*!< Reference to associated interface. */
+ struct server_t *server; /*!< Reference to server */
+ void *data; /*!< Persistent data for I/O handler. */
+ void (*interrupt)(struct iohandler_t *h); /*!< Interrupt handler. */
+
+} iohandler_t;
+
+/*! \brief Round-robin mechanism of switching.
+ */
+#define get_next_rr(current, count) \
+ (((current) + 1) % (count))
+
+/*! \brief Server state flags.
+ */
+typedef enum {
+ ServerIdle = 0 << 0, /*!< Server is idle. */
+ ServerRunning = 1 << 0 /*!< Server is running. */
+} server_state;
+
+/*!
+ * \brief Server interface structure.
+ */
+typedef struct iface_t {
+ struct node *next, *prev;
+ int fd[2]; /*!< \brief Socket filedescriptors (UDP, TCP). */
+ int type[2]; /*!< \brief Socket type. */
+ int port; /*!< \brief Socket port. */
+ char* addr; /*!< \brief Socket address. */
+ iohandler_t* handler[2]; /*!< \brief Associated I/O handlers. */
+} iface_t;
+
+/* Interface indexes. */
+#define UDP_ID 0
+#define TCP_ID 1
+
+/*!
+ * \brief Main server structure.
+ *
+ * Keeps references to all important structures needed for operation.
+ */
+typedef struct server_t {
+
+ /*! \brief Server state tracking. */
+ volatile unsigned state;
+
+ /*! \brief Reference to the name server structure. */
+ knot_nameserver_t *nameserver;
+
+ /*! \brief XFR handler. */
+ xfrhandler_t *xfr_h;
+
+ /*! \brief Event scheduler. */
+ evsched_t *sched;
+
+ /*! \brief I/O handlers list. */
+ list handlers;
+
+ /*! \brief List of interfaces. */
+ list* ifaces;
+
+} server_t;
+
+/*!
+ * \brief Allocates and initializes the server structure.
+ *
+ * Creates all other main structures.
+ *
+ * \retval New instance if successful.
+ * \retval NULL If an error occured.
+ */
+server_t *server_create();
+
+/*!
+ * \brief Create and bind handler to given filedescriptor.
+ *
+ * Pointer to handler instance is used as native unique identifier.
+ * This requests instance not to be reallocated.
+ *
+ * \param server Server structure to be used for operation.
+ * \param fd I/O filedescriptor.
+ * \param unit Threading unit to serve given filedescriptor.
+ *
+ * \retval Handler instance if successful.
+ * \retval NULL If an error occured.
+ */
+iohandler_t *server_create_handler(server_t *server, int fd, dt_unit_t *unit);
+
+/*!
+ * \brief Delete handler.
+ *
+ * \param server Server structure to be used for operation.
+ * \param ref I/O handler instance.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ */
+int server_remove_handler(server_t *server, iohandler_t *ref);
+
+/*!
+ * \brief Starts the server.
+ *
+ * \param server Server structure to be used for operation.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ *
+ * \todo When a module for configuration is added, the filename parameter will
+ * be removed.
+ */
+int server_start(server_t *server);
+
+/*!
+ * \brief Waits for the server to finish.
+ *
+ * \param server Server structure to be used for operation.
+ *
+ * \retval 0 On success (EOK).
+ * \retval <0 If an error occured (EINVAL).
+ */
+int server_wait(server_t *server);
+
+/*!
+ * \brief Requests server to stop.
+ *
+ * \param server Server structure to be used for operation.
+ */
+void server_stop(server_t *server);
+
+/*!
+ * \brief Properly destroys the server structure.
+ *
+ * \param server Server structure to be used for operation.
+ */
+void server_destroy(server_t **server);
+
+/*!
+ * \brief Server config hook.
+ *
+ * Routine for dynamic server reconfiguration.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_ENOTRUNNING if the server is not running.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int server_conf_hook(const struct conf_t *conf, void *data);
+
+#endif // _KNOTD_SERVER_H_
+
+/*! @} */
diff --git a/src/knot/server/socket.c b/src/knot/server/socket.c
new file mode 100644
index 0000000..d3dd664
--- /dev/null
+++ b/src/knot/server/socket.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include "knot/other/error.h"
+#include "knot/common.h"
+#include "knot/server/socket.h"
+
+int socket_create(int family, int type)
+{
+ /* Create socket. */
+ int ret = socket(family, type, 0);
+ if (ret < 0) {
+ return knot_map_errno(EACCES, EINVAL, ENOMEM);
+ }
+
+ return ret;
+}
+
+int socket_connect(int fd, const char *addr, unsigned short port)
+{
+ /* NULL address => any */
+ if (!addr) {
+ addr = "0.0.0.0";
+ }
+
+ /* Resolve address. */
+ int ret = KNOTD_EOK;
+ struct addrinfo hints, *res;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if ((ret = getaddrinfo(addr, NULL, &hints, &res)) != 0) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Evaluate address type. */
+ struct sockaddr *saddr = 0;
+ socklen_t addrlen = 0;
+#ifndef DISABLE_IPV6
+ if (res->ai_family == AF_INET6) {
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)res->ai_addr;
+ ipv6->sin6_port = htons(port);
+ saddr = (struct sockaddr*)ipv6;
+ addrlen = sizeof(struct sockaddr_in6);
+ }
+#endif
+ if (res->ai_family == AF_INET) {
+ struct sockaddr_in *ipv4 = (struct sockaddr_in*)res->ai_addr;
+ ipv4->sin_port = htons(port);
+ saddr = (struct sockaddr*)ipv4;
+ addrlen = sizeof(struct sockaddr_in);
+ }
+
+ /* Connect. */
+ ret = -1;
+ if (addr) {
+ ret = connect(fd, saddr, addrlen);
+ if (ret < 0) {
+ ret = knot_map_errno(EACCES, EADDRINUSE, EAGAIN,
+ ECONNREFUSED, EISCONN);
+ }
+ } else {
+ ret = KNOTD_EINVAL;
+ }
+
+
+ /* Free addresses. */
+ freeaddrinfo(res);
+
+ return ret;
+}
+
+int socket_bind(int socket, int family, const char *addr, unsigned short port)
+{
+ /* Check address family. */
+ struct sockaddr* paddr = 0;
+ socklen_t addrlen = 0;
+ struct sockaddr_in saddr;
+#ifndef DISABLE_IPV6
+ struct sockaddr_in6 saddr6;
+#endif
+ if (family == AF_INET) {
+
+ /* Initialize socket address. */
+ paddr = (struct sockaddr*)&saddr;
+ addrlen = sizeof(saddr);
+ if (getsockname(socket, paddr, &addrlen) < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Set address and port. */
+ saddr.sin_port = htons(port);
+ if (inet_pton(family, addr, &saddr.sin_addr) < 0) {
+ saddr.sin_addr.s_addr = INADDR_ANY;
+ char buf[INET_ADDRSTRLEN];
+ inet_ntop(family, &saddr.sin_addr, buf, sizeof(buf));
+ log_server_error("Address '%s' is invalid, "
+ "using '%s' instead.\n",
+ addr, buf);
+
+ }
+
+ } else {
+
+#ifdef DISABLE_IPV6
+ log_server_error("ipv6 support disabled\n");
+ return KNOTD_ENOIPV6;
+#else
+ /* Initialize socket address. */
+ paddr = (struct sockaddr*)&saddr6;
+ addrlen = sizeof(saddr6);
+ if (getsockname(socket, paddr, &addrlen) < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Set address and port. */
+ saddr6.sin6_port = htons(port);
+ if (inet_pton(family, addr, &saddr6.sin6_addr) < 0) {
+ memcpy(&saddr6.sin6_addr, &in6addr_any, sizeof(in6addr_any));
+ char buf[INET6_ADDRSTRLEN];
+ inet_ntop(family, &saddr6.sin6_addr, buf, sizeof(buf));
+ log_server_error("Address '%s' is invalid, "
+ "using '%s' instead\n",
+ addr, buf);
+
+ }
+#endif
+ }
+
+ /* Reuse old address if taken. */
+ int flag = 1;
+ int ret = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR,
+ &flag, sizeof(flag));
+ if (ret < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Bind to specified address. */
+ int res = bind(socket, paddr, addrlen);
+ if (res < 0) {
+ log_server_error("Cannot bind to socket (%d).\n",
+ errno);
+ return knot_map_errno(EADDRINUSE, EINVAL, EACCES, ENOMEM);
+ }
+
+ return KNOTD_EOK;
+}
+
+int socket_listen(int socket, int backlog_size)
+{
+ int ret = listen(socket, backlog_size);
+ if (ret < 0) {
+ return knot_map_errno(EADDRINUSE);
+ }
+
+ return KNOTD_EOK;
+}
+
+int socket_close(int socket)
+{
+ if (close(socket) < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ return KNOTD_EOK;
+}
+
diff --git a/src/knot/server/socket.h b/src/knot/server/socket.h
new file mode 100644
index 0000000..dff5216
--- /dev/null
+++ b/src/knot/server/socket.h
@@ -0,0 +1,120 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file socket.h
+ *
+ * \author Marek Vavrusa <marek.vavusa@nic.cz>
+ *
+ * \brief Generic sockets APIs.
+ *
+ * This file provides platform-independent sockets.
+ * Functions work on sockets created via system socket(2) functions.
+ *
+ * You can use standard I/O functions send(), sendto(), recv(), recvfrom()
+ * like you would with a normal sockets.
+ *
+ * \addtogroup network
+ * @{
+ */
+
+#ifndef _KNOTD_SOCKET_H_
+#define _KNOTD_SOCKET_H_
+
+/* POSIX only. */
+#include <sys/socket.h>
+#include "common/sockaddr.h"
+
+/*! \brief Socket-related constants. */
+typedef enum {
+ SOCKET_MTU_SZ = 8192, /*!< \todo Determine UDP MTU size. */
+} socket_const_t;
+
+/*!
+ * \brief Create socket.
+ *
+ * \param family Socket family (PF_INET, PF_IPX, PF_PACKET, PF_UNIX).
+ * \param type Socket type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW).
+ *
+ * \retval new socket filedescriptor on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ENOMEM out of memory error.
+ * \retval KNOTD_EACCES process does not have appropriate privileges.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int socket_create(int family, int type);
+
+/*!
+ * \brief Connect to remote host.
+ *
+ * \param fd Socket filedescriptor.
+ * \param addr Requested address.
+ * \param port Requested port.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters.
+ * \retval KNOTD_EACCES process does not have appropriate privileges.
+ * \retval KNOTD_EAGAIN lack of resources, try again.
+ * \retval KNOTD_EADDRINUSE address already in use.
+ * \retval KNOTD_ECONNREFUSED connection refused.
+ * \retval KNOTD_EISCONN already connected.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int socket_connect(int fd, const char *addr, unsigned short port);
+
+/*!
+ * \brief Listen on given socket.
+ *
+ * \param fd Socket filedescriptor.
+ * \param family Socket family.
+ * \param addr Requested address.
+ * \param port Requested port.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters.
+ * \retval KNOTD_EACCES process does not have appropriate privileges.
+ * \retval KNOTD_EADDRINUSE address already in use.
+ * \retval KNOTD_ENOMEM out of memory error.
+ * \retval KNOTD_ENOIPV6 IPv6 support is not available.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int socket_bind(int fd, int family, const char *addr, unsigned short port);
+
+/*!
+ * \brief Listen on given TCP socket.
+ *
+ * \param fd Socket filedescriptor.
+ * \param backlog_size Requested TCP backlog size.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EADDRINUSE address already in use.
+ * \retval KNOTD_ERROR unspecified error.
+ */
+int socket_listen(int fd, int backlog_size);
+
+/*!
+ * \brief Close and deinitialize socket.
+ *
+ * \param fd Socket filedescriptor.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters.
+ */
+int socket_close(int fd);
+
+
+#endif // _KNOTD_SOCKET_H_
+
+/*! @} */
diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c
new file mode 100644
index 0000000..db58fef
--- /dev/null
+++ b/src/knot/server/tcp-handler.c
@@ -0,0 +1,511 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common/sockaddr.h"
+#include "common/skip-list.h"
+#include "common/fdset.h"
+#include "knot/common.h"
+#include "knot/server/tcp-handler.h"
+#include "knot/server/xfr-handler.h"
+#include "libknot/nameserver/name-server.h"
+#include "knot/other/error.h"
+#include "knot/stat/stat.h"
+#include "libknot/util/wire.h"
+#include "knot/server/zones.h"
+
+/*! \brief TCP worker data. */
+typedef struct tcp_worker_t {
+ iohandler_t *ioh; /*!< Shortcut to I/O handler. */
+ fdset_t *fdset; /*!< File descriptor set. */
+ int pipe[2]; /*!< Master-worker signalization pipes. */
+} tcp_worker_t;
+
+/*
+ * Forward decls.
+ */
+
+/*! \brief Wrapper for TCP send. */
+static int xfr_send_cb(int session, sockaddr_t *addr, uint8_t *msg, size_t msglen)
+{
+ UNUSED(addr);
+ return tcp_send(session, msg, msglen);
+}
+
+/*!
+ * \brief TCP event handler function.
+ *
+ * Handle single TCP event.
+ *
+ * \param w Associated I/O event.
+ * \param revents Returned events.
+ */
+static void tcp_handle(tcp_worker_t *w, int fd)
+{
+ if (fd < 0 || !w || !w->ioh) {
+ dbg_net("tcp: tcp_handle(%p, %d) - invalid parameters\n", w, fd);
+ return;
+ }
+
+ dbg_net("tcp: handling TCP event on fd=%d in thread %p.\n",
+ fd, (void*)pthread_self());
+
+ knot_nameserver_t *ns = w->ioh->server->nameserver;
+ xfrhandler_t *xfr_h = w->ioh->server->xfr_h;
+
+ /* Check address type. */
+ sockaddr_t addr;
+ if (sockaddr_init(&addr, w->ioh->type) != KNOTD_EOK) {
+ log_server_error("Socket type %d is not supported, "
+ "IPv6 support is probably disabled.\n",
+ w->ioh->type);
+ return;
+ }
+
+ /* Receive data. */
+ uint8_t qbuf[65535]; /*! \todo This may be problematic. */
+ size_t qbuf_maxlen = sizeof(qbuf);
+ int n = tcp_recv(fd, qbuf, qbuf_maxlen, &addr);
+ if (n <= 0) {
+ dbg_net("tcp: client on fd=%d disconnected\n", fd);
+ fdset_remove(w->fdset, fd);
+ close(fd);
+ return;
+ }
+
+ /* Parse query. */
+// knot_response_t *resp = knot_response_new(qbuf_maxlen);
+ size_t resp_len = qbuf_maxlen; // 64K
+
+ /* Parse query. */
+ knot_packet_type_t qtype = KNOT_QUERY_NORMAL;
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ if (packet == NULL) {
+ uint16_t pkt_id = knot_wire_get_id(qbuf);
+ knot_ns_error_response(ns, pkt_id, KNOT_RCODE_SERVFAIL,
+ qbuf, &resp_len);
+ return;
+ }
+
+ int res = knot_ns_parse_packet(qbuf, n, packet, &qtype);
+ if (unlikely(res != KNOTD_EOK)) {
+
+ /* Send error response on dnslib RCODE. */
+ if (res > 0) {
+ uint16_t pkt_id = knot_wire_get_id(qbuf);
+ knot_ns_error_response(ns, pkt_id, res,
+ qbuf, &resp_len);
+ }
+
+// knot_response_free(&resp);
+ knot_packet_free(&packet);
+ return;
+ }
+
+ /* Handle query. */
+ knot_ns_xfr_t xfr;
+ res = KNOTD_ERROR;
+ switch(qtype) {
+
+ /* Query types. */
+ case KNOT_QUERY_NORMAL:
+ res = knot_ns_answer_normal(ns, packet, qbuf, &resp_len);
+ break;
+ case KNOT_QUERY_IXFR:
+ res = xfr_request_init(&xfr, XFR_TYPE_IOUT, XFR_FLAG_TCP, packet);
+ if (res != KNOTD_EOK) {
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_SERVFAIL, qbuf,
+ &resp_len);
+ res = KNOTD_EOK;
+ break;
+ }
+ xfr.send = xfr_send_cb;
+ xfr.session = fd;
+ memcpy(&xfr.addr, &addr, sizeof(sockaddr_t));
+ xfr_request(xfr_h, &xfr);
+ dbg_net("tcp: enqueued IXFR query on fd=%d\n", fd);
+ return;
+ case KNOT_QUERY_AXFR:
+ res = xfr_request_init(&xfr, XFR_TYPE_AOUT, XFR_FLAG_TCP, packet);
+ if (res != KNOTD_EOK) {
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_SERVFAIL, qbuf,
+ &resp_len);
+ res = KNOTD_EOK;
+ break;
+ }
+ xfr.send = xfr_send_cb;
+ xfr.session = fd;
+ memcpy(&xfr.addr, &addr, sizeof(sockaddr_t));
+ xfr_request(xfr_h, &xfr);
+ dbg_net("tcp: enqueued AXFR query on fd=%d\n", fd);
+ return;
+
+ /*! \todo Implement query notify/update. */
+ case KNOT_QUERY_UPDATE:
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_NOTIMPL, qbuf,
+ &resp_len);
+ res = KNOTD_EOK;
+ break;
+
+ /* Unhandled opcodes. */
+ case KNOT_QUERY_NOTIFY: /*!< Only in UDP. */
+ case KNOT_RESPONSE_NOTIFY: /*!< Only in UDP. */
+ case KNOT_RESPONSE_NORMAL: /*!< TCP handler doesn't send queries. */
+ case KNOT_RESPONSE_AXFR: /*!< Processed in XFR handler. */
+ case KNOT_RESPONSE_IXFR: /*!< Processed in XFR handler. */
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_REFUSED, qbuf,
+ &resp_len);
+ res = KNOTD_EOK;
+ break;
+
+ /* Unknown opcodes. */
+ default:
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_FORMERR, qbuf,
+ &resp_len);
+ res = KNOTD_EOK;
+ break;
+ }
+
+ knot_packet_free(&packet);
+
+ /* Send answer. */
+ if (res == KNOTD_EOK) {
+
+ dbg_net("tcp: got answer of size %zd.\n",
+ resp_len);
+
+ assert(resp_len > 0);
+ res = tcp_send(fd, qbuf, resp_len);
+
+ /* Check result. */
+ if (res != (int)resp_len) {
+ dbg_net("tcp: %s: failed: %d - %d.\n",
+ "socket_send()",
+ res, errno);
+ }
+ } else {
+ dbg_net("tcp: failed to respond to query type=%d on fd=%d - %s\n",
+ qtype, fd, knotd_strerror(res));;
+ }
+
+ return;
+}
+
+static int tcp_accept(int fd)
+{
+ /* Accept incoming connection. */
+ int incoming = accept(fd, 0, 0);
+
+ /* Evaluate connection. */
+ if (incoming < 0) {
+ if (errno != EINTR) {
+ log_server_error("Cannot accept connection "
+ "(%d).\n", errno);
+ }
+ } else {
+ dbg_net("tcp: accepted connection fd=%d\n", incoming);
+ }
+
+ return incoming;
+}
+
+tcp_worker_t* tcp_worker_create()
+{
+ tcp_worker_t *w = malloc(sizeof(tcp_worker_t));
+ if (!w) {
+ dbg_net("tcp: out of memory when creating worker\n");
+ return 0;
+ }
+
+ /* Create signal pipes. */
+ memset(w, 0, sizeof(tcp_worker_t));
+ if (pipe(w->pipe) < 0) {
+ free(w);
+ return 0;
+ }
+
+ /* Create fdset. */
+ w->fdset = fdset_new();
+ if (!w->fdset) {
+ close(w->pipe[0]);
+ close(w->pipe[1]);
+ free(w);
+ }
+
+ fdset_add(w->fdset, w->pipe[0], OS_EV_READ);
+
+ return w;
+}
+
+void tcp_worker_free(tcp_worker_t* w)
+{
+ if (!w) {
+ return;
+ }
+
+ /* Destroy fdset. */
+ fdset_destroy(w->fdset);
+
+ /* Close pipe write end and worker. */
+ close(w->pipe[0]);
+ close(w->pipe[1]);
+ free(w);
+}
+
+/*
+ * Public APIs.
+ */
+
+int tcp_send(int fd, uint8_t *msg, size_t msglen)
+{
+
+ /*! \brief TCP corking.
+ * \see http://vger.kernel.org/~acme/unbehaved.txt
+ */
+#ifdef TCP_CORK
+ int cork = 1;
+ setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork));
+#endif
+
+ /* Send message size. */
+ unsigned short pktsize = htons(msglen);
+ int sent = send(fd, &pktsize, sizeof(pktsize), 0);
+ if (sent < 0) {
+ return KNOTD_ERROR;
+ }
+
+ /* Send message data. */
+ sent = send(fd, msg, msglen, 0);
+ if (sent < 0) {
+ return KNOTD_ERROR;
+ }
+
+#ifdef TCP_CORK
+ /* Uncork. */
+ cork = 0;
+ setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork));
+#endif
+ return sent;
+}
+
+int tcp_recv(int fd, uint8_t *buf, size_t len, sockaddr_t *addr)
+{
+ /* Receive size. */
+ unsigned short pktsize = 0;
+ int n = recv(fd, &pktsize, sizeof(unsigned short), MSG_WAITALL);
+ if (n < 0) {
+ return KNOTD_ERROR;
+ }
+
+ pktsize = ntohs(pktsize);
+
+ // Check packet size for NULL
+ if (pktsize == 0) {
+ return KNOTD_ERROR;
+ }
+
+ dbg_net("tcp: incoming packet size=%hu on fd=%d\n",
+ pktsize, fd);
+
+ // Check packet size
+ if (len < pktsize) {
+ return KNOTD_ENOMEM;
+ }
+
+ /* Receive payload. */
+ n = recv(fd, buf, pktsize, MSG_WAITALL);
+
+ /* Get peer name. */
+ if (addr) {
+ socklen_t alen = addr->len;
+ getpeername(fd, addr->ptr, &alen);
+ }
+
+ dbg_net("tcp: received packet size=%d on fd=%d\n",
+ n, fd);
+
+ return n;
+}
+
+int tcp_loop_master(dthread_t *thread)
+{
+ iohandler_t *handler = (iohandler_t *)thread->data;
+ dt_unit_t *unit = thread->unit;
+ tcp_worker_t **workers = handler->data;
+
+ /* Check socket. */
+ if (!handler || handler->fd < 0 || !workers) {
+ dbg_net("tcp: failed to initialize master thread\n");
+ return KNOTD_EINVAL;
+ }
+
+ /* Accept connections. */
+ int id = 0;
+ dbg_net("tcp: created 1 master with %d workers, backend is '%s' \n",
+ unit->size - 1, fdset_method());
+ while(1) {
+ /* Check for cancellation. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ /* Accept client. */
+ int client = tcp_accept(handler->fd);
+ if (client < 0) {
+ continue;
+ }
+
+ /* Add to worker in RR fashion. */
+ if (write(workers[id]->pipe[1], &client, sizeof(int)) < 0) {
+ dbg_net("tcp: failed to register fd=%d to worker=%d\n",
+ client, id);
+ close(client);
+ continue;
+ }
+ id = get_next_rr(id, unit->size - 1);
+ }
+
+ dbg_net("tcp: master thread finished\n");
+ free(workers);
+
+ return KNOTD_EOK;
+}
+
+int tcp_loop_worker(dthread_t *thread)
+{
+ tcp_worker_t *w = thread->data;
+ if (!w) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Accept clients. */
+ dbg_net_verb("tcp: worker %p started\n", w);
+ for (;;) {
+
+ /* Cancellation point. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ /* Wait for events. */
+ int nfds = fdset_wait(w->fdset);
+ if (nfds <= 0) {
+ continue;
+ }
+
+ /* Process incoming events. */
+ dbg_net_verb("tcp: worker %p registered %d events\n",
+ w, nfds);
+ fdset_it_t it;
+ fdset_begin(w->fdset, &it);
+ while(1) {
+
+ /* Handle incoming clients. */
+ if (it.fd == w->pipe[0]) {
+ int client = 0;
+ if (read(it.fd, &client, sizeof(int)) < 0) {
+ continue;
+ }
+
+ dbg_net_verb("tcp: worker %p registered "
+ "client %d\n",
+ w, client);
+ fdset_add(w->fdset, client, OS_EV_READ);
+ } else {
+ /* Handle other events. */
+ tcp_handle(w, it.fd);
+ }
+
+ /* Check if next exists. */
+ if (fdset_next(w->fdset, &it) != 0) {
+ break;
+ }
+ }
+
+ }
+
+ /* Stop whole unit. */
+ dbg_net_verb("tcp: worker %p finished\n", w);
+ tcp_worker_free(w);
+ return KNOTD_EOK;
+}
+
+int tcp_loop_unit(iohandler_t *ioh, dt_unit_t *unit)
+{
+ if (unit->size < 1) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Create unit data. */
+ tcp_worker_t **workers = malloc((unit->size - 1) *
+ sizeof(tcp_worker_t *));
+ if (!workers) {
+ dbg_net("tcp: cannot allocate list of workers\n");
+ return KNOTD_EINVAL;
+ }
+
+ /* Prepare worker data. */
+ unsigned allocated = 0;
+ for (unsigned i = 0; i < unit->size - 1; ++i) {
+ workers[i] = tcp_worker_create();
+ if (workers[i] == 0) {
+ break;
+ }
+ workers[i]->ioh = ioh;
+ ++allocated;
+ }
+
+ /* Check allocated workers. */
+ if (allocated != unit->size - 1) {
+ for (unsigned i = 0; i < allocated; ++i) {
+ tcp_worker_free(workers[i]);
+ }
+
+ free(workers);
+ dbg_net("tcp: cannot create workers\n");
+ return KNOTD_EINVAL;
+ }
+
+ /* Store worker data. */
+ ioh->data = workers;
+
+ /* Repurpose workers. */
+ for (unsigned i = 0; i < allocated; ++i) {
+ dt_repurpose(unit->threads[i + 1], tcp_loop_worker, workers[i]);
+ }
+
+ /* Repurpose first thread as master (unit controller). */
+ dt_repurpose(unit->threads[0], tcp_loop_master, ioh);
+
+ return KNOTD_EOK;
+}
diff --git a/src/knot/server/tcp-handler.h b/src/knot/server/tcp-handler.h
new file mode 100644
index 0000000..f5fd17a
--- /dev/null
+++ b/src/knot/server/tcp-handler.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file tcp-handler.h
+ *
+ * \author Marek Vavrusa <marek.vavusa@nic.cz>
+ *
+ * \brief TCP sockets threading model.
+ *
+ * The master socket distributes incoming connections among
+ * the worker threads ("buckets"). Each threads processes it's own
+ * set of sockets, and eliminates mutual exclusion problem by doing so.
+ *
+ * \todo Improve documentation of TCP pool API and use proper error codes.
+ *
+ * \addtogroup server
+ * @{
+ */
+
+#ifndef _KNOTD_TCPHANDLER_H_
+#define _KNOTD_TCPHANDLER_H_
+
+#include <stdint.h>
+
+#include "knot/server/socket.h"
+#include "knot/server/server.h"
+#include "knot/server/dthreads.h"
+
+/*!
+ * \brief Send TCP message.
+ *
+ * \param fd Associated socket.
+ * \param msg Buffer for a query wireformat.
+ * \param msglen Buffer maximum size.
+ *
+ * \retval Number of sent data on success.
+ * \retval KNOTD_ERROR on error.
+ */
+int tcp_send(int fd, uint8_t *msg, size_t msglen);
+
+/*!
+ * \brief Send TCP message.
+ *
+ * \param fd Associated socket.
+ * \param buf Buffer for incoming bytestream.
+ * \param len Buffer maximum size.
+ * \param addr Source address.
+ *
+ * \retval Number of read bytes on success.
+ * \retval KNOTD_ERROR on error.
+ * \retval KNOTD_ENOMEM on potential buffer overflow.
+ */
+int tcp_recv(int fd, uint8_t *buf, size_t len, sockaddr_t *addr);
+
+/*!
+ * \brief TCP event loop for accepting connections.
+ *
+ * \param thread Associated thread from DThreads unit.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters.
+ */
+int tcp_loop_master(dthread_t *thread);
+
+/*!
+ * \brief TCP event loop for processing requests.
+ *
+ * \param thread Associated thread from DThreads unit.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters.
+ */
+int tcp_loop_worker(dthread_t *thread);
+
+/*!
+ * \brief Create TCP event handler from threading unit.
+ *
+ * Set-up threading unit for processing TCP requests.
+ *
+ * \param ioh Associated I/O handler.
+ * \param thread Associated thread from DThreads unit.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters.
+ */
+int tcp_loop_unit(iohandler_t *ioh, dt_unit_t *unit);
+
+#endif // _KNOTD_TCPHANDLER_H_
+
+/*! @} */
diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c
new file mode 100644
index 0000000..f7ae550
--- /dev/null
+++ b/src/knot/server/udp-handler.c
@@ -0,0 +1,438 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "common/sockaddr.h"
+#include "knot/common.h"
+#include "knot/other/error.h"
+#include "knot/server/udp-handler.h"
+#include "libknot/nameserver/name-server.h"
+#include "knot/stat/stat.h"
+#include "knot/server/server.h"
+#include "libknot/util/wire.h"
+#include "libknot/consts.h"
+#include "libknot/packet/packet.h"
+#include "knot/server/zones.h"
+#include "knot/server/notify.h"
+
+///*! \brief Wrapper for UDP send. */
+//static int xfr_send_udp(int session, sockaddr_t *addr, uint8_t *msg, size_t msglen)
+//{
+// return sendto(session, msg, msglen, 0, addr->ptr, addr->len);
+//}
+
+int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len,
+ sockaddr_t* addr, knot_nameserver_t *ns)
+{
+ dbg_net("udp: fd=%d received %zd bytes.\n", fd, qbuflen);
+
+ knot_packet_type_t qtype = KNOT_QUERY_NORMAL;
+ *resp_len = SOCKET_MTU_SZ;
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ if (packet == NULL) {
+ dbg_net("udp: failed to create packet on fd=%d\n", fd);
+ uint16_t pkt_id = knot_wire_get_id(qbuf);
+ knot_ns_error_response(ns, pkt_id, KNOT_RCODE_SERVFAIL,
+ qbuf, resp_len);
+ return KNOTD_EOK; /* Created error response. */
+ }
+
+ /* Parse query. */
+ int res = knot_ns_parse_packet(qbuf, qbuflen, packet, &qtype);
+ if (unlikely(res != KNOTD_EOK)) {
+ dbg_net("udp: failed to parse packet on fd=%d\n", fd);
+ /* Send error response on dnslib RCODE. */
+ if (res > 0) {
+ uint16_t pkt_id = knot_wire_get_id(qbuf);
+ knot_ns_error_response(ns, pkt_id, res,
+ qbuf, resp_len);
+ }
+
+ knot_packet_free(&packet);
+ return KNOTD_EOK; /* Created error response. */
+ }
+
+ /* Handle query. */
+// server_t *srv = (server_t *)knot_ns_get_data(ns);
+// knot_ns_xfr_t xfr;
+ res = KNOTD_ERROR;
+ switch(qtype) {
+
+ /* Response types. */
+ case KNOT_RESPONSE_NORMAL:
+ res = zones_process_response(ns, addr, packet,
+ qbuf, resp_len);
+ break;
+ case KNOT_RESPONSE_NOTIFY:
+ res = notify_process_response(ns, packet, addr,
+ qbuf, resp_len);
+ break;
+
+ /* Query types. */
+ case KNOT_QUERY_NORMAL:
+ res = knot_ns_answer_normal(ns, packet, qbuf,
+ resp_len);
+ break;
+ case KNOT_QUERY_AXFR:
+ /* RFC1034, p.28 requires reliable transfer protocol.
+ * Bind responds with FORMERR.
+ */
+ /*! \todo Draft exists for AXFR/UDP, but has not been standardized. */
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_FORMERR, qbuf,
+ resp_len);
+ res = KNOTD_EOK;
+ break;
+
+// /* Process AXFR over UDP. */
+// res = xfr_request_init(&xfr, XFR_TYPE_AOUT, XFR_FLAG_UDP, packet);
+// if (res != KNOTD_EOK) {
+// knot_ns_error_response(ns, knot_packet_id(packet),
+// KNOT_RCODE_SERVFAIL, qbuf,
+// resp_len);
+// res = KNOTD_EOK;
+// break;
+// }
+// xfr.send = xfr_send_udp;
+// xfr.session = dup(fd);
+// memcpy(&xfr.addr, addr, sizeof(sockaddr_t));
+// xfr_request(srv->xfr_h, &xfr);
+// dbg_net("udp: enqueued AXFR query on fd=%d\n", xfr.session);
+// *resp_len = 0;
+// return KNOTD_EOK;
+ case KNOT_QUERY_IXFR:
+ /* According to RFC1035, respond with SOA.
+ * Draft proposes trying to fit response into one packet,
+ * but I have found no tool or slave server to actually attempt
+ * IXFR/UDP.
+ */
+ knot_packet_set_qtype(packet, KNOT_RRTYPE_SOA);
+ res = knot_ns_answer_normal(ns, packet, qbuf,
+ resp_len);
+ break;
+// /* Process IXFR over UDP. */
+// res = xfr_request_init(&xfr, XFR_TYPE_IOUT, XFR_FLAG_UDP, packet);
+// if (res != KNOTD_EOK) {
+// knot_ns_error_response(ns, knot_packet_id(packet),
+// KNOT_RCODE_SERVFAIL, qbuf,
+// resp_len);
+// res = KNOTD_EOK;
+// break;
+// }
+// xfr.send = xfr_send_udp;
+// xfr.session = dup(fd);
+// memcpy(&xfr.addr, addr, sizeof(sockaddr_t));
+// xfr_request(srv->xfr_h, &xfr);
+// dbg_net("udp: enqueued IXFR query on fd=%d\n", xfr.session);
+// *resp_len = 0;
+// return KNOTD_EOK;
+ case KNOT_QUERY_NOTIFY:
+ res = notify_process_request(ns, packet, addr,
+ qbuf, resp_len);
+ break;
+
+ /*! \todo Implement query notify/update. */
+ case KNOT_QUERY_UPDATE:
+ dbg_net("udp: UPDATE query on fd=%d not implemented\n", fd);
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_NOTIMPL, qbuf,
+ resp_len);
+ res = KNOTD_EOK;
+ break;
+
+ /* Unhandled opcodes. */
+ case KNOT_RESPONSE_AXFR: /*!< Processed in XFR handler. */
+ case KNOT_RESPONSE_IXFR: /*!< Processed in XFR handler. */
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_REFUSED, qbuf,
+ resp_len);
+ res = KNOTD_EOK;
+ break;
+
+ /* Unknown opcodes */
+ default:
+ knot_ns_error_response(ns, knot_packet_id(packet),
+ KNOT_RCODE_FORMERR, qbuf,
+ resp_len);
+ res = KNOTD_EOK;
+ break;
+ }
+
+ knot_packet_free(&packet);
+
+ return res;
+}
+
+static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat)
+{
+ iohandler_t *h = (iohandler_t *)thread->data;
+ knot_nameserver_t *ns = h->server->nameserver;
+ int sock = dup(h->fd);
+
+ sockaddr_t addr;
+ if (sockaddr_init(&addr, h->type) != KNOTD_EOK) {
+ log_server_error("Socket type %d is not supported, "
+ "IPv6 support is probably disabled.\n",
+ h->type);
+ return KNOTD_ENOTSUP;
+ }
+
+ uint8_t qbuf[SOCKET_MTU_SZ];
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(struct msghdr));
+ struct iovec iov;
+ memset(&iov, 0, sizeof(struct iovec));
+ iov.iov_base = qbuf;
+ iov.iov_len = SOCKET_MTU_SZ;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = addr.ptr;
+ msg.msg_namelen = addr.len;
+
+ /* Loop until all data is read. */
+ ssize_t n = 0;
+ while (n >= 0) {
+
+ /* Receive packet. */
+ n = recvmsg(sock, &msg, 0);
+
+ /* Cancellation point. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ /* Error and interrupt handling. */
+ if (unlikely(n <= 0)) {
+ if (errno != EINTR && errno != 0) {
+ dbg_net("udp: recvmsg() failed: %d\n",
+ errno);
+ }
+
+ if (!(h->state & ServerRunning)) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ /* Handle received pkt. */
+ size_t resp_len = 0;
+ int rc = udp_handle(sock, qbuf, n, &resp_len, &addr, ns);
+
+ /* Send response. */
+ if (rc == KNOTD_EOK && resp_len > 0) {
+
+ dbg_net("udp: on fd=%d, sending answer size=%zd.\n",
+ sock, resp_len);
+
+ // Send datagram
+ rc = sendto(sock, qbuf, resp_len,
+ 0, addr.ptr, addr.len);
+
+ // Check result
+ if (rc != (int)resp_len) {
+ dbg_net("udp: sendto(): failed: %d - %d.\n",
+ rc, errno);
+ }
+ }
+ }
+
+ /* Free allocd resources. */
+ close(sock);
+
+ return KNOTD_EOK;
+}
+
+#ifdef ENABLE_RECVMMSG
+#ifdef MSG_WAITFORONE
+static inline int udp_master_recvmmsg(dthread_t *thread, stat_t *thread_stat)
+{
+ iohandler_t *h = (iohandler_t *)thread->data;
+ knot_nameserver_t *ns = h->server->nameserver;
+ int sock = dup(h->fd);
+
+ /* Allocate batch for N packets. */
+ char *iobuf = malloc(SOCKET_MTU_SZ * RECVMMSG_BATCHLEN);
+ sockaddr_t *addrs = malloc(sizeof(sockaddr_t) * RECVMMSG_BATCHLEN);
+ struct iovec *iov = malloc(sizeof(struct iovec) * RECVMMSG_BATCHLEN);
+ struct mmsghdr *msgs = malloc(sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
+
+ /* Prepare batch. */
+ memset(msgs, 0, sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
+ for (unsigned i = 0; i < RECVMMSG_BATCHLEN; ++i) {
+ sockaddr_init(addrs + i, h->type);
+ iov[i].iov_base = iobuf + i * SOCKET_MTU_SZ;
+ iov[i].iov_len = SOCKET_MTU_SZ;
+ msgs[i].msg_hdr.msg_iov = iov + i;
+ msgs[i].msg_hdr.msg_iovlen = 1;
+ msgs[i].msg_hdr.msg_name = addrs[i].ptr;
+ msgs[i].msg_hdr.msg_namelen = addrs[i].len;
+ }
+
+ /* Loop until all data is read. */
+ ssize_t n = 0;
+ while (n >= 0) {
+
+ /* Receive multiple messages. */
+ n = recvmmsg(sock, msgs, RECVMMSG_BATCHLEN, MSG_WAITFORONE, 0);
+
+ /* Cancellation point. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ /* Error and interrupt handling. */
+ if (unlikely(n <= 0)) {
+ if (errno != EINTR && errno != 0) {
+ dbg_net("udp: recvmmsg() failed: %d\n",
+ errno);
+ }
+
+ if (!(h->state & ServerRunning)) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ /* Handle each received msg. */
+ int ret = 0;
+ for (unsigned i = 0; i < n; ++i) {
+ struct iovec *cvec = msgs[i].msg_hdr.msg_iov;
+ size_t resp_len = msgs[i].msg_len;
+ ret = udp_handle(sock, cvec->iov_base, resp_len, &resp_len,
+ addrs + i, ns);
+ if (ret == KNOTD_EOK) {
+ msgs[i].msg_len = resp_len;
+ } else {
+ msgs[i].msg_len = 0;
+ }
+
+ }
+
+ /* Gather results. */
+ /*! \todo Implement with sendmmsg() when it's ready. */
+ for (unsigned i = 0; i < n; ++i) {
+ const size_t resp_len = msgs[i].msg_len;
+ if (resp_len > 0) {
+ dbg_net("udp: on fd=%d, sending answer size=%zd.\n",
+ sock, resp_len);
+
+ // Send datagram
+ sockaddr_t *addr = addrs + i;
+ struct iovec *cvec = msgs[i].msg_hdr.msg_iov;
+ int res = sendto(sock, cvec->iov_base, resp_len,
+ 0, addr->ptr, addr->len);
+
+ // Check result
+ if (res != (int)resp_len) {
+ dbg_net("udp: sendto(): failed: %d - %d.\n",
+ res, errno);
+ }
+ }
+ }
+ }
+
+ /* Free allocd resources. */
+ free(iobuf);
+ free(addrs);
+ free(iov);
+ free(msgs);
+ close(sock);
+ return KNOTD_EOK;
+}
+#endif
+#endif
+
+int udp_master(dthread_t *thread)
+{
+ iohandler_t *handler = (iohandler_t *)thread->data;
+ int sock = handler->fd;
+
+ /* Check socket. */
+ if (sock < 0) {
+ dbg_net("udp: null socket recevied, finishing.\n");
+ return KNOTD_EINVAL;
+ }
+
+ /* Set socket options. */
+ int flag = 1;
+#ifndef DISABLE_IPV6
+#
+ if (handler->type == AF_INET6) {
+ /* Disable dual-stack for performance reasons. */
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag));
+
+ /* UDP packets will not exceed a minimum MTU size. */
+ /*flag = IPV6_MIN_MTU;
+ setsockopt(fd, IPPROTO_IPV6, IPV6_MTU, &flag, sizeof(flag));
+ flag = 1; */
+ }
+#endif
+ if (handler->type == AF_INET) {
+
+//#ifdef IP_PMTUDISC_DONT
+// /* Disable fragmentation. */
+// flag = IP_PMTUDISC_DONT;
+// setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag));
+// flag = 1;
+//#endif
+ }
+
+ /* in case of STAT_COMPILE the following code will declare thread_stat
+ * variable in following fashion: stat_t *thread_stat;
+ */
+
+ stat_t *thread_stat = 0;
+ STAT_INIT(thread_stat); //XXX new stat instance every time.
+ stat_set_protocol(thread_stat, stat_UDP);
+
+ /* Execute proper handler. */
+ dbg_net_verb("udp: thread started (worker %p).\n", thread);
+ int ret = KNOTD_EOK;
+
+#ifdef ENABLE_RECVMMSG
+
+/* Check if MSG_WAITFORONE is supported. */
+#ifdef MSG_WAITFORONE
+ ret = udp_master_recvmmsg(thread, thread_stat);
+#else /* Don't have MSG_WAITFORONE */
+ ret = udp_master_recvfrom(thread, thread_stat);
+#endif
+
+#else /* Don't have ENABLE_RECVMMSG */
+ ret = udp_master_recvfrom(thread, thread_stat);
+#endif
+
+
+ stat_free(thread_stat);
+ dbg_net_verb("udp: worker %p finished.\n", thread);
+ return ret;
+}
+
diff --git a/src/knot/server/udp-handler.h b/src/knot/server/udp-handler.h
new file mode 100644
index 0000000..f5fcd04
--- /dev/null
+++ b/src/knot/server/udp-handler.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file udp-handler.h
+ *
+ * \author Marek Vavrusa <marek.vavusa@nic.cz>
+ *
+ * \brief UDP sockets threading model.
+ *
+ * The master socket locks one worker thread at a time
+ * and saves events in it's own backing store for asynchronous processing.
+ * The worker threads work asynchronously in thread pool.
+ *
+ * \addtogroup server
+ * @{
+ */
+
+#ifndef _KNOTD_UDPHANDLER_H_
+#define _KNOTD_UDPHANDLER_H_
+
+#include "knot/server/socket.h"
+#include "knot/server/server.h"
+#include "knot/server/dthreads.h"
+
+/*!
+ * \brief Handle single packet.
+ *
+ * Function processses packet and prepares answer to qbuf,
+ * response length is set to resp_len.
+ *
+ * \param sock
+ * \param qbuf
+ * \param qbuflen
+ * \param resp_len
+ * \param addr
+ * \param ns
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_ERROR
+ * \retval KNOTD_ENOMEM
+ */
+int udp_handle(int sock, uint8_t *qbuf, size_t qbuflen, size_t *resp_len,
+ sockaddr_t* addr, knot_nameserver_t *ns);
+
+/*!
+ * \brief UDP handler thread runnable.
+ *
+ * Listen to DNS datagrams in a loop on a UDP socket and
+ * reply to them. This runnable is designed to be used as coherent
+ * and implements cancellation point.
+ *
+ * \param thread Associated thread from DThreads unit.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters.
+ */
+int udp_master(dthread_t *thread);
+
+#endif
+
+/*! @} */
diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c
new file mode 100644
index 0000000..45817cb
--- /dev/null
+++ b/src/knot/server/xfr-handler.c
@@ -0,0 +1,1296 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <urcu.h>
+
+#include "knot/common.h"
+#include "knot/server/xfr-handler.h"
+#include "libknot/nameserver/name-server.h"
+#include "knot/other/error.h"
+#include "knot/server/socket.h"
+#include "knot/server/udp-handler.h"
+#include "knot/server/tcp-handler.h"
+#include "libknot/updates/xfr-in.h"
+#include "knot/server/zones.h"
+#include "libknot/util/error.h"
+#include "libknot/tsig-op.h"
+#include "common/evsched.h"
+
+void xfr_interrupt(xfrhandler_t *h)
+{
+ for(unsigned i = 0; i < h->unit->size; ++i) {
+ evqueue_write(h->workers[i]->q, "", 1);
+ }
+}
+
+/*!
+ * \brief SOA query timeout handler.
+ */
+static int xfr_udp_timeout(event_t *e)
+{
+ knot_ns_xfr_t *data = (knot_ns_xfr_t *)e->data;
+ if (!data) {
+ return KNOTD_EINVAL;
+ }
+
+ sockaddr_update(&data->addr);
+ char r_addr[SOCKADDR_STRLEN];
+ sockaddr_tostr(&data->addr, r_addr, sizeof(r_addr));
+ int r_port = sockaddr_portnum(&data->addr);
+
+ /* Close socket. */
+ knot_zone_t *z = data->zone;
+ if (z && knot_zone_get_contents(z) && knot_zone_data(z)) {
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(z);
+ log_zone_info("%s '%s' query to %s:%d - timeout exceeded.\n",
+ data->type == XFR_TYPE_SOA ? "SOA" : "NOTIFY",
+ zd->conf->name,
+ r_addr, r_port);
+ }
+
+ knot_ns_xfr_t cr = {};
+ cr.type = XFR_TYPE_CLOSE;
+ cr.session = data->session;
+ cr.data = data;
+ cr.zone = data->zone;
+ xfrworker_t *w = (xfrworker_t *)data->owner;
+ if (w) {
+ evqueue_write(w->q, &cr, sizeof(knot_ns_xfr_t));
+ }
+
+ return KNOTD_EOK;
+}
+
+/*!
+ * \brief Query reponse event handler function.
+ *
+ * Handle single query response event.
+ *
+ * \param loop Associated event pool.
+ * \param w Associated socket watcher.
+ * \param revents Returned events.
+ */
+static int xfr_process_udp_query(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
+{
+ /* Prepare msg header. */
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(struct msghdr));
+ struct iovec iov;
+ memset(&iov, 0, sizeof(struct iovec));
+ iov.iov_base = data->wire;
+ iov.iov_len = data->wire_size;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = data->addr.ptr;
+ msg.msg_namelen = data->addr.len;
+
+ /* Receive msg. */
+ ssize_t n = recvmsg(data->session, &msg, 0);
+ size_t resp_len = data->wire_size;
+ if (n > 0) {
+ udp_handle(fd, data->wire, n, &resp_len, &data->addr, w->ns);
+ }
+
+ /* Disable timeout. */
+ evsched_t *sched =
+ ((server_t *)knot_ns_get_data(w->ns))->sched;
+ event_t *ev = (event_t *)data->data;
+ if (ev) {
+ dbg_xfr("xfr: cancelling UDP query timeout\n");
+ evsched_cancel(sched, ev);
+ ev = (event_t *)data->data;
+ if (ev) {
+ evsched_event_free(sched, ev);
+ data->data = 0;
+ }
+
+ /* Close after receiving response. */
+ knot_ns_xfr_t cr = {};
+ cr.type = XFR_TYPE_CLOSE;
+ cr.session = data->session;
+ cr.data = data;
+ cr.zone = data->zone;
+ evqueue_write(w->q, &cr, sizeof(knot_ns_xfr_t));
+ }
+
+ return KNOTD_EOK;
+}
+
+/*! \todo Document me. */
+static void xfr_free_task(knot_ns_xfr_t *task)
+{
+ if (!task) {
+ return;
+ }
+
+ xfrworker_t *w = (xfrworker_t *)task->owner;
+ if (!w) {
+ free(task);
+ return;
+ }
+
+ /* Remove from fdset. */
+ if (w->fdset) {
+ dbg_xfr("xfr_free_task: freeing fd=%d.\n", task->session);
+ fdset_remove(w->fdset, task->session);
+ }
+
+ /* Unlock if XFR/IN.*/
+ if (task->type == XFR_TYPE_AIN || task->type == XFR_TYPE_IIN) {
+ knot_zone_t *zone = task->zone;
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ if (zd) {
+ zd->xfr_in.wrkr = 0;
+ pthread_mutex_unlock(&zd->xfr_in.lock);
+ }
+ }
+
+ /* Remove fd-related data. */
+ xfrhandler_t *h = w->master;
+ pthread_mutex_lock(&h->tasks_mx);
+ skip_remove(h->tasks, (void*)((size_t)task->session), 0, 0);
+ pthread_mutex_unlock(&h->tasks_mx);
+
+ /*! \todo Free data. */
+ close(task->session);
+ free(task);
+}
+
+/*! \todo Document me. */
+static knot_ns_xfr_t *xfr_register_task(xfrworker_t *w, knot_ns_xfr_t *req)
+{
+ knot_ns_xfr_t *t = malloc(sizeof(knot_ns_xfr_t));
+ if (!t) {
+ return 0;
+ }
+
+ memcpy(t, req, sizeof(knot_ns_xfr_t));
+ sockaddr_update(&t->addr);
+
+ /* Update request. */
+ t->wire = 0; /* Invalidate shared buffer. */
+ t->wire_size = 0;
+ t->data = 0; /* New zone will be built. */
+
+ /* Register data. */
+ xfrhandler_t * h = w->master;
+ pthread_mutex_lock(&h->tasks_mx);
+ skip_insert(h->tasks, (void*)((ssize_t)t->session), t, 0);
+ pthread_mutex_unlock(&h->tasks_mx);
+
+ /* Add to set. */
+ fdset_add(w->fdset, t->session, OS_EV_READ);
+ t->owner = w;
+ return t;
+}
+
+/*!
+ * \brief Clean pending transfer data.
+ */
+static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data)
+{
+ int ret = KNOTD_EOK;
+ knot_changesets_t *chs = 0;
+
+ switch(data->type) {
+ case XFR_TYPE_AIN:
+ if (data->data) {
+ knot_zone_contents_deep_free(
+ (knot_zone_contents_t **)&data->data, 0);
+ data->data = 0;
+ }
+ break;
+ case XFR_TYPE_IIN:
+ if (data->data) {
+ chs = (knot_changesets_t *)data->data;
+ knot_free_changesets(&chs);
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * \brief Finalize XFR/IN transfer.
+ *
+ * \param w XFR worker.
+ * \param data Associated data.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_ERROR
+ */
+static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data)
+{
+ knot_zone_t *zone = (knot_zone_t *)data->zone;
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ const char *zorigin = zd->conf->name;
+
+ /* CLEANUP */
+// // get the zone name from Question
+// dbg_xfr_verb("Query: %p, response: %p\n", data->query, data->response);
+// const knot_dname_t *qname = knot_packet_qname(data->query);
+// char *zorigin = "(unknown)";
+// if (qname != NULL) {
+// zorigin = knot_dname_to_str(qname);
+// }
+
+ int ret = KNOTD_EOK;
+
+ switch(data->type) {
+ case XFR_TYPE_AIN:
+ dbg_xfr("xfr: AXFR/IN saving new zone\n");
+ ret = zones_save_zone(data);
+ if (ret != KNOTD_EOK) {
+ xfr_xfrin_cleanup(w, data);
+ log_zone_error("AXFR failed to save "
+ "transferred zone '%s/IN' - %s\n",
+ zorigin, knotd_strerror(ret));
+ } else {
+ dbg_xfr("xfr: AXFR/IN new zone saved.\n");
+ ret = knot_ns_switch_zone(w->ns, data);
+ if (ret != KNOTD_EOK) {
+ log_zone_error("AXFR failed to "
+ "switch in-memory zone "
+ "'%s/IN' - %s\n",
+ zorigin,
+ knotd_strerror(ret));
+ }
+ }
+ log_zone_info("AXFR transfer of zone '%s/IN' "
+ "%s.\n", zorigin,
+ ret == KNOTD_EOK ? "finished" : "failed");
+ break;
+ case XFR_TYPE_IIN:
+ /* Save changesets. */
+ dbg_xfr("xfr: IXFR/IN saving changesets\n");
+ ret = zones_store_changesets(data);
+ if (ret != KNOTD_EOK) {
+ log_zone_error("IXFR failed to save "
+ "transferred changesets "
+ "for zone '%s/IN' - %s\n",
+ zorigin, knotd_strerror(ret));
+ } else {
+ /* Update zone. */
+ ret = zones_apply_changesets(data);
+ if (ret != KNOTD_EOK) {
+ log_zone_error("IXFR failed to "
+ "apply changesets to "
+ "zone '%s/IN' - %s\n",
+ zorigin,
+ knotd_strerror(ret));
+ }
+ }
+ /* Free changesets, but not the data. */
+ knot_changesets_t *chs = (knot_changesets_t *)data->data;
+ knot_free_changesets(&chs);
+ /* CLEANUP */
+// free(chs->sets);
+// free(chs);
+ data->data = 0;
+ log_zone_info("IXFR transfer of zone '%s/IN' "
+ "%s.\n", zorigin,
+ ret == KNOTD_EOK ? "finished" : "failed");
+ break;
+ default:
+ ret = KNOTD_EINVAL;
+ break;
+ }
+
+ /* CLEANUP */
+// if (qname != NULL) {
+// free(zorigin);
+// }
+
+ return ret;
+}
+
+/*!
+ * \brief Prepare TSIG for XFR.
+ */
+static int xfr_prepare_tsig(knot_ns_xfr_t *xfr, knot_key_t *key)
+{
+ int ret = KNOT_EOK;
+ xfr->tsig_key = 0; /*key;*/ /*!< \todo [TSIG] DISABLED */
+// xfr->tsig_size = tsig_wire_maxsize(key);
+// xfr->digest_max_size = tsig_alg_digest_length(
+// key->algorithm);
+// xfr->digest = malloc(xfr->digest_max_size);
+// memset(xfr->digest, 0 , xfr->digest_max_size);
+// dbg_xfr("xfr: found TSIG key (MAC len=%zu), adding to transfer\n",
+// xfr->digest_max_size);
+
+ return ret;
+}
+
+/*!
+ * \brief Check TSIG if exists.
+ */
+static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode)
+{
+ /*!< \todo [TSIG] DISABLED */
+ return knot_packet_parse_rest(xfr->query);
+
+// /* Parse rest of the packet. */
+// int ret = KNOT_EOK;
+// knot_packet_t *qry = xfr->query;
+// knot_key_t *key = 0;
+// const knot_rrset_t *tsig_rr = 0;
+// ret = knot_packet_parse_rest(qry);
+// if (ret == KNOT_EOK) {
+
+// /* Find TSIG key name from query. */
+// const knot_dname_t* kname = 0;
+// int tsig_pos = knot_packet_additional_rrset_count(qry) - 1;
+// if (tsig_pos >= 0) {
+// tsig_rr = knot_packet_additional_rrset(qry, tsig_pos);
+// if (knot_rrset_type(tsig_rr) == KNOT_RRTYPE_TSIG) {
+// dbg_xfr("xfr: found TSIG in AR\n");
+// kname = knot_rrset_owner(tsig_rr);
+// ret = KNOT_TSIG_EBADKEY;
+// }
+// }
+// if (!kname) {
+// dbg_xfr("xfr: TSIG not found in AR\n");
+// }
+
+// /* Find configured key for claimed key name. */
+// conf_key_t *ck = 0;
+// WALK_LIST(ck, conf()->keys) {
+// if (!kname) {
+// break;
+// }
+// /* Compare stored keys to claimed. */
+// if (knot_dname_compare(ck->k.name,
+// kname) == 0) {
+// dbg_xfr("xfr: found claimed "
+// "TSIG key for "
+// "comparison\n");
+// key = &ck->k;
+// break;
+// }
+// }
+
+// /* Validate with TSIG. */
+// if (key) {
+// /* Prepare variables for TSIG */
+// xfr_prepare_tsig(xfr, key);
+
+// /* Copy MAC from query. */
+// dbg_xfr("xfr: validating TSIG from query\n");
+// const uint8_t* mac = tsig_rdata_mac(tsig_rr);
+// size_t mac_len = tsig_rdata_mac_length(tsig_rr);
+// if (mac_len > xfr->digest_max_size) {
+// ret = KNOT_EMALF;
+// dbg_xfr("xfr: MAC length %zu exceeds digest "
+// "maximum size %zu\n",
+// mac_len, xfr->digest_max_size);
+// } else {
+// memcpy(xfr->digest, mac, mac_len);
+// xfr->digest_size = mac_len;
+
+// /* Check query TSIG. */
+// ret = knot_tsig_server_check(
+// tsig_rr,
+// knot_packet_wireformat(qry),
+// knot_packet_size(qry),
+// key);
+// dbg_xfr("knot_tsig_server_check() returned %s\n",
+// knot_strerror(ret));
+// }
+
+// /* Evaluate TSIG check results. */
+// switch(ret) {
+// case KNOT_EOK:
+// *rcode = KNOT_RCODE_NOERROR;
+// break;
+// case KNOT_TSIG_EBADKEY:
+// case KNOT_TSIG_EBADSIG:
+// // delete the TSIG key so that the error
+// // response is not signed
+// xfr->tsig_key = NULL;
+// case KNOT_TSIG_EBADTIME:
+// /*! \note [TSIG] Set TSIG rcode in TSIG RR. */
+
+// *rcode = KNOT_RCODE_NOTAUTH;
+// break;
+// case KNOT_EMALF:
+// *rcode = KNOT_RCODE_FORMERR;
+// break;
+// default:
+// *rcode = KNOT_RCODE_SERVFAIL;
+// }
+// } else {
+// dbg_xfr("xfr: no claimed key configured, "
+// "treating as bad key\n");
+// }
+// } else {
+// dbg_xfr("xfr: failed to parse rest of the packet\n");
+// *rcode = KNOT_RCODE_FORMERR;
+// }
+
+// return ret;
+}
+
+/*!
+ * \brief XFR-IN event handler function.
+ *
+ * Handle single XFR client event.
+ *
+ * \param w Associated XFR worker.
+ * \param fd Associated file descriptor.
+ * \param data Transfer data.
+ */
+int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
+{
+ /* Buffer for answering. */
+ uint8_t buf[65535];
+
+ /* Update xfer state. */
+ data->wire = buf;
+ data->wire_size = sizeof(buf);
+
+ /* Handle SOA/NOTIFY responses. */
+ if (data->type == XFR_TYPE_NOTIFY || data->type == XFR_TYPE_SOA) {
+ return xfr_process_udp_query(w, fd, data);
+ }
+
+ /* Read DNS/TCP packet. */
+ int ret = 0;
+ int rcvd = tcp_recv(fd, buf, sizeof(buf), 0);
+ data->wire_size = rcvd;
+ if (rcvd <= 0) {
+ data->wire_size = 0;
+ ret = KNOT_ECONN;
+ } else {
+
+ /*!
+ * \todo [TSIG] Somewhere before this fetch the query digest and the TSIG
+ * associated with this transfer and save them to 'data'.
+ */
+
+ /* Process incoming packet. */
+ switch(data->type) {
+ case XFR_TYPE_AIN:
+ ret = knot_ns_process_axfrin(w->ns, data);
+ break;
+ case XFR_TYPE_IIN:
+ ret = knot_ns_process_ixfrin(w->ns, data);
+ break;
+ default:
+ ret = KNOT_EBADARG;
+ break;
+ }
+ }
+
+ /* AXFR-style IXFR. */
+ if (ret == KNOT_ENOIXFR) {
+ dbg_xfr("xfr: Fallback to AXFR/IN.\n");
+ assert(data->type == XFR_TYPE_IIN);
+ data->type = XFR_TYPE_AIN;
+ ret = knot_ns_process_axfrin(w->ns, data);
+ }
+
+ /* Check return code for errors. */
+ dbg_xfr_verb("xfr: processed incoming XFR packet (res = %d)\n", ret);
+
+ /* Finished xfers. */
+ int xfer_finished = 0;
+ if (ret != KNOT_EOK) {
+ xfer_finished = 1;
+ }
+
+ /* IXFR refused, try again with AXFR. */
+ knot_zone_t *zone = (knot_zone_t *)data->zone;
+ if (zone && data->type == XFR_TYPE_IIN && ret == KNOT_EXFRREFUSED) {
+ log_server_notice("IXFR/IN failed, attempting to use "
+ "AXFR/IN instead.\n");
+ size_t bufsize = sizeof(buf);
+ data->wire_size = sizeof(buf); /* Reset maximum bufsize */
+ ret = xfrin_create_axfr_query(zone->name, data,
+ &bufsize, 1);
+ /* Send AXFR/IN query. */
+ if (ret == KNOTD_EOK) {
+ ret = data->send(data->session, &data->addr,
+ data->wire, bufsize);
+ /* Switch to AIN type XFR and return now. */
+ if (ret == bufsize) {
+ data->type = XFR_TYPE_AIN;
+ return KNOTD_EOK;
+ }
+ }
+ }
+
+ /* Handle errors. */
+ if (ret < 0 && ret != KNOT_ENOXFR) {
+ log_server_error("%cXFR/IN request failed - %s\n",
+ data->type == XFR_TYPE_AIN ? 'A' : 'I',
+ knot_strerror(ret));
+ }
+
+ /* Check finished zone. */
+ if (xfer_finished) {
+
+ knot_zone_t *zone = (knot_zone_t *)data->zone;
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ const char *zorigin = zd->conf->name;
+
+ /* Only for successful xfers. */
+ if (ret > 0) {
+ ret = xfr_xfrin_finalize(w, data);
+
+ /* AXFR bootstrap timeout. */
+ rcu_read_lock();
+ if (!knot_zone_contents(zone) && data->type == XFR_TYPE_AIN) {
+ /* Schedule request (60 - 90s random delay). */
+ int tmr_s = AXFR_BOOTSTRAP_RETRY;
+ tmr_s += (30.0 * 1000) * (rand() / (RAND_MAX + 1.0));
+ zd->xfr_in.bootstrap_retry = tmr_s;
+ log_zone_info("Another attempt to AXFR bootstrap "
+ "zone '%s' in %d seconds.\n",
+ zorigin, tmr_s/1000);
+ }
+ rcu_read_unlock();
+
+ /* Update timers. */
+ server_t *server = (server_t *)knot_ns_get_data(w->ns);
+ zones_timers_update(zone, zd->conf, server->sched);
+
+ } else {
+ /* Cleanup */
+ xfr_xfrin_cleanup(w, data);
+ }
+
+ /* Free TSIG buffers. */
+ if (data->digest) {
+ free(data->digest);
+ data->digest = 0;
+ data->digest_size = 0;
+ }
+ if (data->tsig_data) {
+ free(data->tsig_data);
+ data->tsig_data = 0;
+ data->tsig_data_size = 0;
+ }
+
+ /* Disconnect. */
+ ret = KNOTD_ECONNREFUSED; /* Make it disconnect. */
+ } else {
+ ret = KNOTD_EOK;
+ }
+
+ return ret;
+}
+
+/*! \todo Document me.
+ */
+static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data)
+{
+ /* Fetch associated zone. */
+ knot_zone_t *zone = (knot_zone_t *)data->zone;
+ if (!zone) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Check if not already processing. */
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ if (!zd) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Enqueue to worker that has zone locked for XFR/IN. */
+ int ret = pthread_mutex_trylock(&zd->xfr_in.lock);
+ if (ret != 0) {
+ dbg_xfr_verb("xfr: XFR/IN switching to another thread, "
+ "zone '%s' is already in transfer\n",
+ zd->conf->name);
+ xfrworker_t *nextw = (xfrworker_t *)zd->xfr_in.wrkr;
+ if (nextw == 0) {
+ nextw = w;
+ }
+ evqueue_write(nextw->q, data, sizeof(knot_ns_xfr_t));
+ return KNOTD_EOK;
+ } else {
+ zd->xfr_in.wrkr = w;
+ }
+
+ /* Update address. */
+ sockaddr_update(&data->addr);
+ char r_addr[SOCKADDR_STRLEN];
+ sockaddr_tostr(&data->addr, r_addr, sizeof(r_addr));
+ int r_port = sockaddr_portnum(&data->addr);
+
+ /* Connect to remote. */
+ if (data->session <= 0) {
+ int fd = socket_create(data->addr.family, SOCK_STREAM);
+ if (fd < 0) {
+ log_server_warning("Failed to create socket "
+ "(type=%s, family=%s).\n",
+ "SOCK_STREAM",
+ data->addr.family == AF_INET ?
+ "AF_INET" : "AF_INET6");
+ return KNOTD_ERROR;
+ }
+ ret = connect(fd, data->addr.ptr, data->addr.len);
+ if (ret < 0) {
+ log_server_warning("Failed to connect to %cXFR master "
+ "at %s:%d.\n",
+ data->type == XFR_TYPE_AIN ? 'A' : 'I',
+ r_addr, r_port);
+ if (!knot_zone_contents(zone)) {
+ /* Reschedule request (120 - 240s random delay). */
+ int tmr_s = AXFR_BOOTSTRAP_RETRY * 2; /* Malus x2 */
+ tmr_s += (int)((120.0 * 1000) *
+ (rand() / (RAND_MAX + 1.0)));
+ event_t *ev = zd->xfr_in.timer;
+ if (ev) {
+ evsched_cancel(ev->parent, ev);
+ evsched_schedule(ev->parent, ev, tmr_s);
+ }
+ log_zone_notice("Zone AXFR bootstrap failed, "
+ "another attempt in %d seconds."
+ "\n", tmr_s / 1000);
+ }
+ return KNOTD_ERROR;
+ }
+
+ /* Store new socket descriptor. */
+ data->session = fd;
+ } else {
+ /* Duplicate existing socket descriptor. */
+ data->session = dup(data->session);
+ }
+
+ /* Fetch zone contents. */
+ rcu_read_lock();
+ const knot_zone_contents_t *contents = knot_zone_contents(zone);
+ if (!contents && data->type == XFR_TYPE_IIN) {
+ rcu_read_unlock();
+ log_server_warning("Failed start IXFR on zone with no "
+ "contents\n");
+ return KNOTD_ERROR;
+ }
+
+ /*! \todo [TSIG] Somewhere before this determine if the server should
+ * use TSIG for this transfer and set appropriate fields
+ * in 'data'.
+ */
+ int add_tsig = 0;
+ if (data->tsig_key) {
+ if (xfr_prepare_tsig(data, data->tsig_key) == KNOT_EOK) {
+ size_t data_bufsize = KNOT_NS_TSIG_DATA_MAX_SIZE;
+ data->tsig_data = malloc(data_bufsize);
+ if (data->tsig_data) {
+ dbg_xfr("xfr: using TSIG for XFR/IN\n");
+ add_tsig = 1;
+ data->tsig_data_size = data_bufsize;
+ } else {
+ dbg_xfr("xfr: failed to allocate TSIG data "
+ "buffer (%zu kB)\n",
+ data_bufsize / 1024);
+ }
+ }
+ }
+
+ /* Create XFR query. */
+ size_t bufsize = data->wire_size;
+ switch(data->type) {
+ case XFR_TYPE_AIN:
+ ret = xfrin_create_axfr_query(zone->name, data, &bufsize, add_tsig);
+ break;
+ case XFR_TYPE_IIN:
+ ret = xfrin_create_ixfr_query(contents, data, &bufsize, add_tsig);
+ break;
+ default:
+ ret = KNOTD_EINVAL;
+ break;
+ }
+
+ /* Handle errors. */
+ if (ret != KNOT_EOK) {
+ dbg_xfr("xfr: failed to create XFR query type %d: %s\n",
+ data->type, knot_strerror(ret));
+ return ret;
+ }
+
+ /* Unlock zone contents. */
+ rcu_read_unlock();
+
+ /* Add to pending transfers. */
+ knot_ns_xfr_t *task = xfr_register_task(w, data);
+
+ ret = data->send(data->session, &data->addr, data->wire, bufsize);
+ if (ret != bufsize) {
+ log_server_notice("Failed to send %cXFR query.",
+ data->type == XFR_TYPE_AIN ? 'A' : 'I');
+ xfr_free_task(task);
+ return KNOTD_ERROR;
+ }
+
+ /* Send XFR query. */
+ log_server_info("%cXFR transfer of zone '%s/IN' with %s:%d started.\n",
+ data->type == XFR_TYPE_AIN ? 'A' : 'I',
+ zd->conf->name,
+ r_addr, r_port);
+
+ return KNOTD_EOK;
+}
+
+static int xfr_fd_compare(void *k1, void *k2)
+{
+ if (k1 < k2) {
+ return -1;
+ }
+
+ if (k1 > k2) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Public APIs.
+ */
+
+static xfrworker_t* xfr_worker_create(xfrhandler_t *h, knot_nameserver_t *ns)
+{
+ xfrworker_t *w = malloc(sizeof(xfrworker_t));
+ if(!w) {
+ return 0;
+ }
+
+ /* Set nameserver and master. */
+ w->ns = ns;
+ w->master = h;
+
+ /* Create event queue. */
+ w->q = evqueue_new();
+ if (!w->q) {
+ free(w);
+ return 0;
+ }
+
+ /* Create fdset. */
+ w->fdset = fdset_new();
+ if (!w->fdset) {
+ evqueue_free(&w->q);
+ free(w);
+ return 0;
+ }
+
+ /* Add evqueue to fdset. */
+ fdset_add(w->fdset, evqueue_pollfd(w->q), OS_EV_READ);
+
+ return w;
+}
+
+static void xfr_worker_free(xfrworker_t *w) {
+ if (w) {
+ evqueue_free(&w->q);
+ fdset_destroy(w->fdset);
+ free(w);
+ }
+}
+
+xfrhandler_t *xfr_create(size_t thrcount, knot_nameserver_t *ns)
+{
+ /* Create XFR handler data. */
+ xfrhandler_t *data = malloc(sizeof(xfrhandler_t));
+ if (!data) {
+ return 0;
+ }
+ memset(data, 0, sizeof(xfrhandler_t));
+
+ /* Create RR mutex. */
+ pthread_mutex_init(&data->rr_mx, 0);
+
+ /* Create tasks structure and mutex. */
+ pthread_mutex_init(&data->tasks_mx, 0);
+ data->tasks = skip_create_list(xfr_fd_compare);
+
+ /* Initialize threads. */
+ data->workers = malloc(thrcount * sizeof(xfrhandler_t*));
+ if(data->workers == 0) {
+ pthread_mutex_destroy(&data->rr_mx);
+ free(data);
+ }
+
+ /* Create threading unit. */
+ dt_unit_t *unit = dt_create(thrcount);
+ if (!unit) {
+ pthread_mutex_destroy(&data->rr_mx);
+ free(data->workers);
+ free(data);
+ return 0;
+ }
+ data->unit = unit;
+
+ /* Create worker threads. */
+ unsigned initialized = 0;
+ for (unsigned i = 0; i < thrcount; ++i) {
+ data->workers[i] = xfr_worker_create(data, ns);
+ if(data->workers[i] == 0) {
+ break;
+ }
+ ++initialized;
+ }
+
+ /* Check for initialized. */
+ if (initialized != thrcount) {
+ for (unsigned i = 0; i < initialized; ++i) {
+ xfr_worker_free(data->workers[i]);
+ }
+ pthread_mutex_destroy(&data->rr_mx);
+ free(data->workers);
+ free(data->unit);
+ free(data);
+ return 0;
+ }
+
+ /* Assign worker threads. */
+ for (unsigned i = 0; i < thrcount; ++i) {
+ dt_repurpose(unit->threads[i], xfr_worker, data->workers[i]);
+ }
+
+ data->interrupt = xfr_interrupt;
+
+ return data;
+}
+
+int xfr_free(xfrhandler_t *handler)
+{
+ if (!handler) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Free RR mutex. */
+ pthread_mutex_destroy(&handler->rr_mx);
+
+ /* Free tasks and mutex. */
+ skip_destroy_list(&handler->tasks, 0,
+ (void(*)(void*))xfr_free_task);
+ pthread_mutex_destroy(&handler->tasks_mx);
+
+ /* Free workers. */
+ for (unsigned i = 0; i < handler->unit->size; ++i) {
+ xfr_worker_free(handler->workers[i]);
+ }
+ free(handler->workers);
+
+ /* Delete unit. */
+ dt_delete(&handler->unit);
+ free(handler);
+
+ return KNOTD_EOK;
+}
+
+int xfr_stop(xfrhandler_t *handler)
+{
+ /* Break loop. */
+ dt_stop(handler->unit);
+ return KNOTD_EOK;
+}
+
+int xfr_join(xfrhandler_t *handler) {
+ return dt_join(handler->unit);
+}
+
+int xfr_request_init(knot_ns_xfr_t *r, int type, int flags, knot_packet_t *pkt)
+{
+ if (!r || type < 0 || flags < 0) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Blank and init. */
+ memset(r, 0, sizeof(knot_ns_xfr_t));
+ r->type = type;
+ r->flags = flags;
+
+ /* Copy packet if applicable. */
+ if (pkt != 0) {
+ uint8_t *wire_copy = malloc(sizeof(uint8_t) * pkt->size);
+ if (!wire_copy) {
+ ERR_ALLOC_FAILED;
+ return KNOTD_ENOMEM;
+ }
+ memcpy(wire_copy, pkt->wireformat, pkt->size);
+ pkt->wireformat = wire_copy;
+ r->query = pkt;
+ }
+
+ return KNOTD_EOK;
+}
+
+int xfr_request(xfrhandler_t *handler, knot_ns_xfr_t *req)
+{
+ if (!handler || !req) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Get next worker in RR fashion */
+ pthread_mutex_lock(&handler->rr_mx);
+ evqueue_t *q = handler->workers[handler->rr]->q;
+ handler->rr = get_next_rr(handler->rr, handler->unit->size);
+ pthread_mutex_unlock(&handler->rr_mx);
+
+ /* Delegate request. */
+ int ret = evqueue_write(q, req, sizeof(knot_ns_xfr_t));
+ if (ret < 0) {
+ return KNOTD_ERROR;
+ }
+
+ return KNOTD_EOK;
+}
+
+static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen)
+{
+ /* Read single request. */
+ knot_ns_xfr_t xfr = {};
+ int ret = evqueue_read(w->q, &xfr, sizeof(knot_ns_xfr_t));
+ if (ret != sizeof(knot_ns_xfr_t)) {
+ dbg_xfr_verb("xfr: evqueue_read() returned %d.\n", ret);
+ return KNOTD_ENOTRUNNING;
+ }
+
+ /* Update request. */
+ sockaddr_update(&xfr.addr);
+ xfr.wire = buf;
+ xfr.wire_size = buflen;
+ char r_addr[SOCKADDR_STRLEN];
+ sockaddr_tostr(&xfr.addr, r_addr, sizeof(r_addr));
+ int r_port = sockaddr_portnum(&xfr.addr);
+
+ conf_read_lock();
+
+ /* Handle request. */
+ knot_ns_xfr_t *task = 0;
+ evsched_t *sch = 0;
+ const char *req_type = "";
+ knot_rcode_t rcode = 0;
+ char *zname = "(unknown)";
+
+ /* XFR request state tracking. */
+ int init_failed = 0;
+ const char *errstr = "";
+ const knot_dname_t *qname = NULL;
+
+ dbg_xfr_verb("Query ptr: %p\n", xfr.query);
+
+ dbg_xfr_verb("xfr: processing request type '%d'\n", xfr.type);
+ switch(xfr.type) {
+ case XFR_TYPE_AOUT:
+ req_type = "AXFR/OUT";
+ ret = knot_ns_init_xfr(w->ns, &xfr);
+ init_failed = (ret != KNOT_EOK);
+ errstr = knot_strerror(ret);
+
+ // use the QNAME as the zone name to get names also for
+ // zones that are not in the server
+ qname = knot_packet_qname(xfr.query);
+ if (qname != NULL) {
+ zname = knot_dname_to_str(qname);
+ }
+
+ /* Check requested zone. */
+ if (!init_failed) {
+ ret = zones_xfr_check_zone(&xfr, &rcode);
+ init_failed = (ret != KNOTD_EOK);
+ errstr = knotd_strerror(ret);
+ }
+
+ /* Check TSIG. */
+ if (!init_failed) {
+ ret = xfr_check_tsig(&xfr, &rcode);
+ init_failed = (ret != KNOT_EOK);
+ errstr = knot_strerror(ret);
+ }
+
+ /* Evaluate progress and answer if passed. */
+ if (init_failed) {
+ knot_ns_xfr_send_error(w->ns, &xfr, rcode);
+ socket_close(xfr.session);
+ log_server_notice("AXFR transfer of zone '%s/OUT' "
+ "%s:%d failed: %s\n",
+ zname,
+ r_addr, r_port,
+ errstr);
+ } else {
+ ret = knot_ns_answer_axfr(w->ns, &xfr);
+ dbg_xfr("xfr: ns_answer_axfr() = %d.\n", ret);
+ if (ret != KNOTD_EOK) {
+ socket_close(xfr.session);
+ } else {
+ log_server_info("AXFR transfer of zone '%s/OUT' "
+ "to %s:%d successful.\n",
+ zname,
+ r_addr, r_port);
+ }
+ }
+
+ if (xfr.digest) {
+ free(xfr.digest);
+ xfr.digest_max_size = 0;
+ xfr.digest = 0;
+ }
+ free(xfr.query->wireformat);
+ xfr.query->wireformat = 0;
+ knot_packet_free(&xfr.query); /* Free query. */
+
+ if (qname != NULL) {
+ free(zname);
+ }
+
+ break;
+ case XFR_TYPE_IOUT:
+ req_type = "IXFR/OUT";
+ ret = knot_ns_init_xfr(w->ns, &xfr);
+ init_failed = (ret != KNOT_EOK);
+ errstr = knot_strerror(ret);
+
+ qname = knot_packet_qname(xfr.query);
+ if (qname != NULL) {
+ zname = knot_dname_to_str(qname);
+ }
+
+ /* Check requested zone. */
+ if (!init_failed) {
+ ret = zones_xfr_check_zone(&xfr, &rcode);
+ init_failed = (ret != KNOTD_EOK);
+ errstr = knotd_strerror(ret);
+ }
+
+ /* Check TSIG. */
+ if (!init_failed) {
+ ret = xfr_check_tsig(&xfr, &rcode);
+ init_failed = (ret != KNOT_EOK);
+ errstr = knot_strerror(ret);
+ }
+
+ uint32_t serial_from = 0;
+ uint32_t serial_to = 0;
+
+ // Check serial differeces
+ if (!init_failed) {
+ dbg_xfr_verb("Loading serials for IXFR.\n");
+ ret = ns_ixfr_load_serials(&xfr, &serial_from,
+ &serial_to);
+ dbg_xfr_detail("Loaded serials: from: %u, to: %u\n",
+ serial_from, serial_to);
+ init_failed = (ret != KNOT_EOK);
+ errstr = knot_strerror(ret);
+ }
+
+ /* Load changesets from journal. */
+ if (!init_failed) {
+ dbg_xfr_verb("Loading changesets from journal.\n");
+ ret = zones_xfr_load_changesets(&xfr, serial_from,
+ serial_to);
+ if (ret != KNOTD_EOK) {
+ /* History cannot be reconstructed, fallback to AXFR. */
+ if (ret == KNOTD_ERANGE || ret == KNOTD_ENOENT) {
+ log_server_info("IXFR transfer of zone '%s/OUT'"
+ " - failed to load data from journal: %s."
+ " Fallback to AXFR.\n",
+ knotd_strerror(ret), zname);
+ xfr.type = XFR_TYPE_AOUT;
+ xfr_request(w->master, &xfr);
+ conf_read_unlock();
+ return KNOTD_EOK;
+ } else if (ret == KNOTD_EMALF) {
+ rcode = KNOT_RCODE_FORMERR;
+ } else {
+ rcode = KNOT_RCODE_SERVFAIL;
+ }
+ init_failed = (ret != KNOTD_EOK);
+ errstr = knotd_strerror(ret);
+ }
+ }
+
+ /* Evaluate progress and answer if passed. */
+ if (init_failed) {
+ knot_ns_xfr_send_error(w->ns, &xfr, rcode);
+ log_server_notice("IXFR transfer of zone '%s/OUT' "
+ "%s:%d failed: %s\n",
+ zname,
+ r_addr, r_port,
+ errstr);
+ ret = KNOTD_ERROR;
+ } else {
+ ret = knot_ns_answer_ixfr(w->ns, &xfr);
+ dbg_xfr("xfr: ns_answer_ixfr() = %d.\n", ret);
+ if (ret != KNOTD_EOK) {
+ socket_close(xfr.session);
+ } else {
+ log_server_info("IXFR transfer of zone '%s/OUT'"
+ " - not enough data in journal,"
+ " fallback to AXFR.\n",
+ zname);
+ xfr.type = XFR_TYPE_AOUT;
+ xfr_request(w->master, &xfr);
+ return KNOTD_EOK;
+ }
+ }
+ if (xfr.digest) {
+ free(xfr.digest);
+ xfr.digest = 0;
+ xfr.digest_max_size = 0;
+ }
+ free(xfr.query->wireformat);
+ knot_packet_free(&xfr.query); /* Free query. */
+
+ if (qname) {
+ free(zname);
+ }
+
+ break;
+ case XFR_TYPE_AIN:
+ req_type = "AXFR/IN";
+ case XFR_TYPE_IIN:
+ if (xfr.type == XFR_TYPE_IIN) {
+ req_type = "IXFR/IN";
+ }
+
+ ret = xfr_client_start(w, &xfr);
+
+ /* Report. */
+ if (ret != KNOTD_EOK && ret != KNOTD_EACCES) {
+ log_server_error("%s request from %s:%d failed: %s\n",
+ req_type, r_addr, r_port,
+ knotd_strerror(ret));
+ }
+ break;
+ case XFR_TYPE_SOA:
+ case XFR_TYPE_NOTIFY:
+ /* Register task. */
+ task = xfr_register_task(w, &xfr);
+ if (!task) {
+ ret = KNOTD_ENOMEM;
+ break;
+ }
+
+ req_type = "SOA or NOTIFY";
+ dbg_xfr("xfr: waiting for %s query response\n",
+ xfr.type == XFR_TYPE_SOA ? "SOA" : "NOTIFY");
+
+ /* Add timeout. */
+ sch = ((server_t *)knot_ns_get_data(w->ns))->sched;
+ task->data = evsched_schedule_cb(sch, xfr_udp_timeout,
+ task, SOA_QRY_TIMEOUT);
+ ret = KNOTD_EOK;
+ break;
+ /* Socket close event. */
+ case XFR_TYPE_CLOSE:
+ xfr_free_task((knot_ns_xfr_t *)xfr.data);
+ ret = KNOTD_EOK;
+ default:
+ break;
+ }
+
+ conf_read_unlock();
+
+ return ret;
+}
+
+int xfr_worker(dthread_t *thread)
+{
+ xfrworker_t *w = (xfrworker_t *)thread->data;
+
+ /* Check data. */
+ if (w < 0) {
+ dbg_xfr("xfr: NULL worker data, worker cancelled\n");
+ return KNOTD_EINVAL;
+ }
+
+ /* Buffer for answering. */
+ uint8_t buf[65535];
+
+ /* Accept requests. */
+ int ret = 0;
+ dbg_xfr_verb("xfr: worker=%p starting\n", w);
+ for (;;) {
+
+ /* Check for cancellation. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ /* Poll fdset. */
+ int nfds = fdset_wait(w->fdset);
+ if (nfds <= 0) {
+ continue;
+ }
+
+ /* Check for cancellation. */
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ /* Iterate fdset. */
+ xfrhandler_t *h = w->master;
+ knot_ns_xfr_t *data = 0;
+ int rfd = evqueue_pollfd(w->q);
+ fdset_it_t it;
+ fdset_begin(w->fdset, &it);
+ while(1) {
+
+ /* Check if it request. */
+ if (it.fd == rfd) {
+ dbg_xfr_verb("xfr: worker=%p processing request\n",
+ w);
+ ret = xfr_process_request(w, buf, sizeof(buf));
+ if (ret == KNOTD_ENOTRUNNING) {
+ break;
+ }
+ } else {
+ /* Find data. */
+ pthread_mutex_lock(&h->tasks_mx);
+ data = skip_find(h->tasks, (void*)((size_t)it.fd));
+ pthread_mutex_unlock(&h->tasks_mx);
+ dbg_xfr_verb("xfr: worker=%p processing event on "
+ "fd=%d data=%p.\n",
+ w, it.fd, data);
+ ret = xfr_process_event(w, it.fd, data);
+ if (ret != KNOTD_EOK) {
+ xfr_free_task(data);
+ }
+ }
+
+ /* Next fd. */
+ if (fdset_next(w->fdset, &it) < 0) {
+ break;
+ }
+ }
+ }
+
+
+ /* Stop whole unit. */
+ dbg_xfr_verb("xfr: worker=%p finished.\n", w);
+ thread->data = 0;
+ return KNOTD_EOK;
+}
diff --git a/src/knot/server/xfr-handler.h b/src/knot/server/xfr-handler.h
new file mode 100644
index 0000000..3587d93
--- /dev/null
+++ b/src/knot/server/xfr-handler.h
@@ -0,0 +1,163 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file xfr-handler.h
+ *
+ * \author Marek Vavrusa <marek.vavusa@nic.cz>
+ *
+ * \brief XFR requests handler.
+ *
+ * \addtogroup server
+ * @{
+ */
+
+#ifndef _KNOTD_XFRHANDLER_H_
+#define _KNOTD_XFRHANDLER_H_
+
+#include "knot/server/dthreads.h"
+#include "libknot/nameserver/name-server.h"
+#include "common/evqueue.h"
+#include "common/fdset.h"
+#include "common/skip-list.h" /*!< \todo Consider another data struct. */
+
+struct xfrhandler_t;
+
+/*!
+ * \brief XFR worker structure.
+ */
+typedef struct xfrworker_t
+{
+ knot_nameserver_t *ns; /*!< \brief Pointer to nameserver.*/
+ evqueue_t *q; /*!< \brief Shared XFR requests queue.*/
+ fdset_t *fdset; /*!< \brief File descriptor set. */
+ struct xfrhandler_t *master; /*! \brief Worker master. */
+} xfrworker_t;
+
+/*!
+ * \brief XFR handler structure.
+ */
+typedef struct xfrhandler_t
+{
+ dt_unit_t *unit; /*!< \brief Threading unit. */
+ xfrworker_t **workers; /*!< \brief Workers. */
+ skip_list_t *tasks; /*!< \brief Pending tasks. */
+ pthread_mutex_t tasks_mx; /*!< \brief Tasks synchronisation. */
+ void (*interrupt)(struct xfrhandler_t *h); /*!< Interrupt handler. */
+ unsigned rr; /*!< \brief Round-Robin counter. */
+ pthread_mutex_t rr_mx; /*!< \brief RR mutex. */
+} xfrhandler_t;
+
+/*!
+ * \brief Create XFR threading unit.
+ *
+ * Unit can be controlled by standard DThreads API.
+ * Unit is created in Idle mode.
+ *
+ * \param thrcount Requested number of threads.
+ * \param ns Pointer to nameserver.
+ *
+ * \retval New handler on success.
+ * \retval NULL on error.
+ */
+xfrhandler_t *xfr_create(size_t thrcount, knot_nameserver_t *ns);
+
+/*!
+ * \brief Delete XFR handler.
+ *
+ * \warning Threading unit must be stopped and joined.
+ *
+ * \param handler XFR handler.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on NULL handler.
+ * \retval KNOTD_ERROR on error.
+ */
+int xfr_free(xfrhandler_t *handler);
+
+/*!
+ * \brief Start XFR handler.
+ *
+ * \param handler XFR handler.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_ERROR on error.
+ */
+static inline int xfr_start(xfrhandler_t *handler) {
+ return dt_start(handler->unit);
+}
+
+/*!
+ * \brief Stop XFR handler.
+ *
+ * \param handler XFR handler.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_ERROR on error.
+ */
+int xfr_stop(xfrhandler_t *handler);
+
+/*!
+ * \brief Wait for XFR handler to finish.
+ *
+ * \param handler XFR handler.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_ERROR on error.
+ */
+int xfr_join(xfrhandler_t *handler);
+
+/*!
+ * \brief Prepare XFR request.
+ *
+ * \param r XFR request.
+ * \param type Request type.
+ * \param flags Request flags.
+ * \param pkt Query packet or NULL.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_ENOMEM
+ * \retval KNOTD_EINVAL
+ */
+int xfr_request_init(knot_ns_xfr_t *r, int type, int flags, knot_packet_t *pkt);
+
+/*!
+ * \brief Enqueue XFR request.
+ *
+ * \param handler XFR handler instance.
+ * \param req XFR request.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on NULL handler or request.
+ * \retval KNOTD_ERROR on error.
+ */
+int xfr_request(xfrhandler_t *handler, knot_ns_xfr_t *req);
+
+/*!
+ * \brief XFR master runnable.
+ *
+ * Processes incoming AXFR/IXFR requests asynchonously.
+ * When no thread is available at the moment, request is enqueued.
+ *
+ * \param thread Associated thread from DThreads unit.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL invalid parameters.
+ */
+int xfr_worker(dthread_t *thread);
+
+#endif // _KNOTD_XFRHANDLER_H_
+
+/*! @} */
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
new file mode 100644
index 0000000..4456dac
--- /dev/null
+++ b/src/knot/server/zones.c
@@ -0,0 +1,2352 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/stat.h>
+
+#include "common/lists.h"
+#include "libknot/dname.h"
+#include "libknot/util/wire.h"
+#include "knot/zone/zone-dump-text.h"
+#include "knot/zone/zone-load.h"
+#include "libknot/zone/zone.h"
+#include "libknot/zone/zonedb.h"
+#include "knot/conf/conf.h"
+#include "knot/other/debug.h"
+#include "knot/other/error.h"
+#include "knot/other/log.h"
+#include "knot/server/notify.h"
+#include "knot/server/server.h"
+#include "libknot/updates/xfr-in.h"
+#include "knot/server/zones.h"
+#include "libknot/util/error.h"
+#include "knot/zone/zone-dump.h"
+#include "libknot/nameserver/name-server.h"
+#include "libknot/updates/changesets.h"
+
+static const size_t XFRIN_CHANGESET_BINARY_SIZE = 100;
+static const size_t XFRIN_CHANGESET_BINARY_STEP = 100;
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Wrapper for TCP send.
+ * \todo Implement generic fd pool properly with callbacks.
+ */
+#include "knot/server/tcp-handler.h"
+static int zones_send_cb(int fd, sockaddr_t *addr, uint8_t *msg, size_t msglen)
+{
+ return tcp_send(fd, msg, msglen);
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Zone data destructor function. */
+static int zonedata_destroy(knot_zone_t *zone)
+{
+ dbg_zones_verb("zones: zonedata_destroy(%p) called\n", zone);
+
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ if (!zd) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Cancel REFRESH timer. */
+ if (zd->xfr_in.timer) {
+ evsched_t *sch = zd->xfr_in.timer->parent;
+ evsched_cancel(sch, zd->xfr_in.timer);
+ evsched_event_free(sch, zd->xfr_in.timer);
+ zd->xfr_in.timer = 0;
+ }
+
+ /* Cancel EXPIRE timer. */
+ if (zd->xfr_in.expire) {
+ evsched_t *sch = zd->xfr_in.expire->parent;
+ evsched_cancel(sch, zd->xfr_in.expire);
+ evsched_event_free(sch, zd->xfr_in.expire);
+ zd->xfr_in.expire = 0;
+ }
+
+ /* Remove list of pending NOTIFYs. */
+ pthread_mutex_lock(&zd->lock);
+ notify_ev_t *ev = 0, *evn = 0;
+ WALK_LIST_DELSAFE(ev, evn, zd->notify_pending) {
+ zones_cancel_notify(zd, ev);
+ }
+ pthread_mutex_unlock(&zd->lock);
+
+ /* Cancel IXFR DB sync timer. */
+ if (zd->ixfr_dbsync) {
+ evsched_t *sch = zd->ixfr_dbsync->parent;
+ evsched_cancel(sch, zd->ixfr_dbsync);
+ evsched_event_free(sch, zd->ixfr_dbsync);
+ zd->ixfr_dbsync = 0;
+ }
+
+ /* Destroy mutex. */
+ pthread_mutex_destroy(&zd->lock);
+ pthread_mutex_destroy(&zd->xfr_in.lock);
+
+ acl_delete(&zd->xfr_in.acl);
+ acl_delete(&zd->xfr_out);
+ acl_delete(&zd->notify_in);
+ acl_delete(&zd->notify_out);
+
+ /* Close IXFR db. */
+ journal_close(zd->ixfr_db);
+
+ free(zd);
+
+ /* Invalidate. */
+ zone->dtor = 0;
+ zone->data = 0;
+
+ return KNOTD_EOK;
+}
+
+/*! \brief Zone data constructor function. */
+static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone)
+{
+ zonedata_t *zd = malloc(sizeof(zonedata_t));
+ if (!zd) {
+ return KNOTD_ENOMEM;
+ }
+
+ /* Link to config. */
+ zd->conf = cfg;
+ zd->server = 0;
+
+ /* Initialize mutex. */
+ pthread_mutex_init(&zd->lock, 0);
+
+ /* Initialize ACLs. */
+ zd->xfr_out = 0;
+ zd->notify_in = 0;
+ zd->notify_out = 0;
+
+ /* Initialize XFR-IN. */
+ sockaddr_init(&zd->xfr_in.master, -1);
+ zd->xfr_in.timer = 0;
+ zd->xfr_in.expire = 0;
+ zd->xfr_in.next_id = -1;
+ zd->xfr_in.acl = 0;
+ zd->xfr_in.wrkr = 0;
+ zd->xfr_in.bootstrap_retry = 0;
+ pthread_mutex_init(&zd->xfr_in.lock, 0);
+
+ /* Initialize NOTIFY. */
+ init_list(&zd->notify_pending);
+
+ /* Initialize IXFR database. */
+ zd->ixfr_db = journal_open(cfg->ixfr_db, cfg->ixfr_fslimit,
+ JOURNAL_DIRTY);
+ if (!zd->ixfr_db) {
+ int ret = journal_create(cfg->ixfr_db, JOURNAL_NCOUNT);
+ if (ret != KNOTD_EOK) {
+ log_server_error("Failed to create journal file "
+ "'%s'\n", cfg->ixfr_db);
+ }
+ zd->ixfr_db = journal_open(cfg->ixfr_db, cfg->ixfr_fslimit,
+ JOURNAL_DIRTY);
+ }
+
+ if (zd->ixfr_db == 0) {
+ log_server_error("Failed to open journal file "
+ "'%s'\n", cfg->ixfr_db);
+ }
+
+ /* Initialize IXFR database syncing event. */
+ zd->ixfr_dbsync = 0;
+
+ /* Set and install destructor. */
+ zone->data = zd;
+ zone->dtor = zonedata_destroy;
+
+ /* Set zonefile SOA serial. */
+ const knot_rrset_t *soa_rrs = 0;
+ const knot_rdata_t *soa_rr = 0;
+
+ /* Load serial. */
+ zd->zonefile_serial = 0;
+ const knot_zone_contents_t *contents = knot_zone_contents(zone);
+ if (contents) {
+ soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA);
+ soa_rr = knot_rrset_rdata(soa_rrs);
+ int64_t serial = knot_rdata_soa_serial(soa_rr);
+ zd->zonefile_serial = (uint32_t)serial;
+ if (serial < 0) {
+ return KNOTD_EINVAL;
+ }
+ }
+
+ return KNOTD_EOK;
+}
+
+/*!
+ * \brief Return SOA timer value.
+ *
+ * \param zone Pointer to zone.
+ * \param rr_func RDATA specificator.
+ * \return Timer in miliseconds.
+ */
+static uint32_t zones_soa_timer(knot_zone_t *zone,
+ uint32_t (*rr_func)(const knot_rdata_t*))
+{
+ if (!zone) {
+ dbg_zones_verb("zones: zones_soa_timer() called "
+ "with NULL zone\n");
+ }
+
+ uint32_t ret = 0;
+
+ /* Retrieve SOA RDATA. */
+ const knot_rrset_t *soa_rrs = 0;
+ const knot_rdata_t *soa_rr = 0;
+ knot_zone_contents_t * zc = knot_zone_get_contents((zone));
+ if (!zc) {
+ return 0;
+ }
+
+ soa_rrs = knot_node_rrset(knot_zone_contents_apex(zc),
+ KNOT_RRTYPE_SOA);
+ soa_rr = knot_rrset_rdata(soa_rrs);
+ ret = rr_func(soa_rr);
+
+ /* Convert to miliseconds. */
+ return ret * 1000;
+}
+
+/*!
+ * \brief Return SOA REFRESH timer value.
+ *
+ * \param zone Pointer to zone.
+ * \return REFRESH timer in miliseconds.
+ */
+static uint32_t zones_soa_refresh(knot_zone_t *zone)
+{
+ return zones_soa_timer(zone, knot_rdata_soa_refresh);
+}
+
+/*!
+ * \brief Return SOA RETRY timer value.
+ *
+ * \param zone Pointer to zone.
+ * \return RETRY timer in miliseconds.
+ */
+static uint32_t zones_soa_retry(knot_zone_t *zone)
+{
+ return zones_soa_timer(zone, knot_rdata_soa_retry);
+}
+
+/*!
+ * \brief Return SOA EXPIRE timer value.
+ *
+ * \param zone Pointer to zone.
+ * \return EXPIRE timer in miliseconds.
+ */
+static uint32_t zones_soa_expire(knot_zone_t *zone)
+{
+ return zones_soa_timer(zone, knot_rdata_soa_expire);
+}
+
+/*!
+ * \brief XFR/IN expire event handler.
+ */
+static int zones_expire_ev(event_t *e)
+{
+ rcu_read_lock();
+ dbg_zones("zones: EXPIRE timer event\n");
+ knot_zone_t *zone = (knot_zone_t *)e->data;
+ if (!zone) {
+ return KNOTD_EINVAL;
+ }
+ if (!zone->data) {
+ return KNOTD_EINVAL;
+ }
+
+ zonedata_t *zd = (zonedata_t *)zone->data;
+
+ /* Won't accept any pending SOA responses. */
+ zd->xfr_in.next_id = -1;
+
+ /* Mark the zone as expired. This will remove the zone contents. */
+ knot_zone_contents_t *contents = knot_zonedb_expire_zone(
+ zd->server->nameserver->zone_db, zone->name);
+
+ if (contents == NULL) {
+ log_server_warning("Non-existent zone expired. Ignoring.\n");
+ rcu_read_unlock();
+ return 0;
+ }
+
+
+ rcu_read_unlock();
+
+ dbg_zones_verb("zones: zone %s expired, waiting for xfers to finish\n",
+ zd->conf->name);
+ pthread_mutex_lock(&zd->xfr_in.lock);
+ dbg_zones_verb("zones: zone %s locked, no xfers are running\n",
+ zd->conf->name);
+
+ synchronize_rcu();
+ pthread_mutex_unlock(&zd->xfr_in.lock);
+
+ log_server_info("Zone '%s' expired.\n", zd->conf->name);
+
+ /* Early finish this event to prevent lockup during cancellation. */
+ dbg_zones("zones: zone expired, removing from database\n");
+ evsched_event_finished(e->parent);
+
+ /* Cancel REFRESH timer. */
+ if (zd->xfr_in.timer) {
+ evsched_cancel(e->parent, zd->xfr_in.timer);
+ evsched_event_free(e->parent, zd->xfr_in.timer);
+ zd->xfr_in.timer = 0;
+ }
+
+ /* Free EXPIRE timer. */
+ if (zd->xfr_in.expire) {
+ evsched_event_free(e->parent, zd->xfr_in.expire);
+ zd->xfr_in.expire = 0;
+ }
+
+ knot_zone_contents_deep_free(&contents, 0);
+
+ return 0;
+}
+
+/*!
+ * \brief Zone REFRESH or RETRY event.
+ */
+static int zones_refresh_ev(event_t *e)
+{
+ dbg_zones("zones: REFRESH or RETRY timer event\n");
+ knot_zone_t *zone = (knot_zone_t *)e->data;
+ if (!zone) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Cancel pending timers. */
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ if (!zd) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Prepare buffer for query. */
+ uint8_t qbuf[SOCKET_MTU_SZ];
+ size_t buflen = SOCKET_MTU_SZ;
+
+ /* Lock RCU. */
+ rcu_read_lock();
+
+ /* Check for contents. */
+ if (!knot_zone_contents(zone)) {
+
+ /* Bootstrap from XFR master. */
+ knot_ns_xfr_t xfr_req;
+ memset(&xfr_req, 0, sizeof(knot_ns_xfr_t));
+ memcpy(&xfr_req.addr, &zd->xfr_in.master, sizeof(sockaddr_t));
+ xfr_req.data = (void *)zone;
+ xfr_req.send = zones_send_cb;
+
+ /* Select transfer method. */
+ xfr_req.type = XFR_TYPE_AIN;
+ xfr_req.zone = zone;
+
+ /* Select TSIG key. */
+ /*!< \todo [TSIG] DISABLED */
+ xfr_req.tsig_key = 0;
+// if (zd->xfr_in.tsig_key.name) {
+// xfr_req.tsig_key = &zd->xfr_in.tsig_key;
+// }
+
+ /* Unlock zone contents. */
+ rcu_read_unlock();
+
+ /* Enqueue XFR request. */
+ int locked = pthread_mutex_trylock(&zd->xfr_in.lock);
+ if (locked != 0) {
+ dbg_zones("zones: already bootstrapping '%s'\n",
+ zd->conf->name);
+ return KNOTD_EOK;
+ } else {
+ log_zone_info("Attempting to bootstrap zone %s from master\n",
+ zd->conf->name);
+ pthread_mutex_unlock(&zd->xfr_in.lock);
+ }
+
+ return xfr_request(zd->server->xfr_h, &xfr_req);
+ }
+
+ /* Do not issue SOA query if transfer is pending. */
+ int locked = pthread_mutex_trylock(&zd->xfr_in.lock);
+ if (locked != 0) {
+ dbg_zones("zones: zone '%s' is being transferred, "
+ "deferring SOA query\n",
+ zd->conf->name);
+
+ /* Reschedule as RETRY timer. */
+ evsched_schedule(e->parent, e, zones_soa_retry(zone));
+ dbg_zones("zones: RETRY of '%s' after %u seconds\n",
+ zd->conf->name, zones_soa_retry(zone) / 1000);
+
+ /* Unlock RCU. */
+ rcu_read_unlock();
+ return KNOTD_EOK;
+ } else {
+ pthread_mutex_unlock(&zd->xfr_in.lock);
+ }
+
+ /* Create query. */
+ /*! \todo API for retrieval of name. */
+
+ /*! \todo [TSIG] CHANGE!!! only for compatibility now. */
+ knot_ns_xfr_t xfr_req;
+ memset(&xfr_req, 0, sizeof(knot_ns_xfr_t));
+ xfr_req.wire = qbuf;
+
+ int ret = xfrin_create_soa_query(zone->name, &xfr_req, &buflen);
+ if (ret == KNOT_EOK) {
+
+ sockaddr_t *master = &zd->xfr_in.master;
+
+ /* Create socket on random port. */
+ int sock = socket_create(master->family, SOCK_DGRAM);
+
+ /* Send query. */
+ ret = -1;
+ if (sock > -1) {
+ ret = sendto(sock, qbuf, buflen, 0,
+ master->ptr, master->len);
+ }
+
+ /* Store ID of the awaited response. */
+ if (ret == buflen) {
+ zd->xfr_in.next_id = knot_wire_get_id(qbuf);
+ dbg_zones("zones: expecting SOA response "
+ "ID=%d for '%s'\n",
+ zd->xfr_in.next_id, zd->conf->name);
+ }
+
+ /* Watch socket. */
+ knot_ns_xfr_t req;
+ memset(&req, 0, sizeof(req));
+ req.session = sock;
+ req.type = XFR_TYPE_SOA;
+ req.zone = zone;
+ memcpy(&req.addr, master, sizeof(sockaddr_t));
+ sockaddr_update(&req.addr);
+ xfr_request(zd->server->xfr_h, &req);
+ } else {
+ ret = KNOTD_ERROR;
+ }
+
+ /* Schedule EXPIRE timer on first attempt. */
+ if (!zd->xfr_in.expire) {
+ uint32_t expire_tmr = zones_soa_expire(zone);
+ zd->xfr_in.expire = evsched_schedule_cb(
+ e->parent,
+ zones_expire_ev,
+ zone, expire_tmr);
+ dbg_zones("zones: EXPIRE of '%s' after %u seconds\n",
+ zd->conf->name, expire_tmr / 1000);
+ }
+
+ /* Reschedule as RETRY timer. */
+ evsched_schedule(e->parent, e, zones_soa_retry(zone));
+ dbg_zones("zones: RETRY of '%s' after %u seconds\n",
+ zd->conf->name, zones_soa_retry(zone) / 1000);
+
+ /* Unlock RCU. */
+ rcu_read_unlock();
+
+ return ret;
+}
+
+/*!
+ * \brief Send NOTIFY to slave server.
+ */
+static int zones_notify_send(event_t *e)
+{
+ dbg_notify("notify: NOTIFY timer event\n");
+
+ notify_ev_t *ev = (notify_ev_t *)e->data;
+ knot_zone_t *zone = ev->zone;
+ if (!zone) {
+ log_zone_error("notify: NOTIFY invalid event received\n");
+ evsched_event_free(e->parent, e);
+ free(ev);
+ return KNOTD_EINVAL;
+ }
+
+ /* Check for answered/cancelled query. */
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ knot_zone_contents_t *contents = knot_zone_get_contents(zone);
+
+ /* Reduce number of available retries. */
+ --ev->retries;
+
+ /* Check number of retries. */
+ if (ev->retries < 0) {
+ log_server_notice("NOTIFY query maximum number of retries "
+ "for zone %s exceeded.\n",
+ zd->conf->name);
+ pthread_mutex_lock(&zd->lock);
+ rem_node(&ev->n);
+ evsched_event_free(e->parent, e);
+ free(ev);
+ pthread_mutex_unlock(&zd->lock);
+ return KNOTD_EMALF;
+ }
+
+ /* Prepare buffer for query. */
+ uint8_t qbuf[SOCKET_MTU_SZ];
+ size_t buflen = sizeof(qbuf);
+
+ /* RFC suggests 60s, but it is configurable. */
+ int retry_tmr = ev->timeout * 1000;
+
+ /* Reschedule. */
+ conf_read_lock();
+ evsched_schedule(e->parent, e, retry_tmr);
+ dbg_notify("notify: Query RETRY after %u secs (zone '%s')\n",
+ retry_tmr / 1000, zd->conf->name);
+ conf_read_unlock();
+
+ /* Create query. */
+ int ret = notify_create_request(contents, qbuf, &buflen);
+ if (ret == KNOTD_EOK && zd->server) {
+
+ /* Lock RCU. */
+ rcu_read_lock();
+
+ /* Create socket on random port. */
+ int sock = socket_create(ev->addr.family, SOCK_DGRAM);
+
+ /* Send query. */
+ ret = -1;
+ if (sock > -1) {
+ ret = sendto(sock, qbuf, buflen, 0,
+ ev->addr.ptr, ev->addr.len);
+ }
+
+ /* Store ID of the awaited response. */
+ if (ret == buflen) {
+ char r_addr[SOCKADDR_STRLEN];
+ sockaddr_tostr(&ev->addr, r_addr, sizeof(r_addr));
+ int r_port = sockaddr_portnum(&ev->addr);
+ ev->msgid = knot_wire_get_id(qbuf);
+ log_server_info("Issued NOTIFY query to %s:%d, expecting "
+ "response ID=%d\n",
+ r_addr, r_port,
+ ev->msgid);
+
+ }
+
+ /* Watch socket. */
+ knot_ns_xfr_t req;
+ memset(&req, 0, sizeof(req));
+ req.session = sock;
+ req.type = XFR_TYPE_NOTIFY;
+ req.zone = zone;
+ memcpy(&req.addr, &ev->addr, sizeof(sockaddr_t));
+ xfr_request(zd->server->xfr_h, &req);
+
+ /* Unlock RCU */
+ rcu_read_unlock();
+ }
+
+ return ret;
+}
+
+/*! \brief Function for marking nodes as synced and updated. */
+static int zones_ixfrdb_sync_apply(journal_t *j, journal_node_t *n)
+{
+ /* Check for dirty bit (not synced to permanent storage). */
+ if (n->flags & JOURNAL_DIRTY) {
+
+ /* Remove dirty bit. */
+ n->flags = n->flags & ~JOURNAL_DIRTY;
+
+ /* Sync. */
+ journal_update(j, n);
+ }
+
+ return KNOTD_EOK;
+}
+
+/*!
+ * \brief Sync chagnes in zone to zonefile.
+ */
+static int zones_zonefile_sync_ev(event_t *e)
+{
+ dbg_zones("zones: IXFR database SYNC timer event\n");
+
+ /* Fetch zone. */
+ knot_zone_t *zone = (knot_zone_t *)e->data;
+ if (!zone) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Fetch zone data. */
+ zonedata_t *zd = (zonedata_t *)zone->data;
+ if (!zd) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Execute zonefile sync. */
+ int ret = zones_zonefile_sync(zone);
+ if (ret == KNOTD_EOK) {
+ log_zone_info("Applied differences of '%s' to zonefile.\n",
+ zd->conf->name);
+ } else {
+ log_zone_warning("Failed to apply differences of '%s' "
+ "to zonefile.\n",
+ zd->conf->name);
+ }
+
+ /* Reschedule. */
+ conf_read_lock();
+ evsched_schedule(e->parent, e, zd->conf->dbsync_timeout * 1000);
+ dbg_zones("zones: next IXFR database SYNC of '%s' in %d seconds\n",
+ zd->conf->name, zd->conf->dbsync_timeout);
+ conf_read_unlock();
+
+ return ret;
+}
+
+/*!
+ * \brief Update ACL list from configuration.
+ *
+ * \param acl Pointer to existing or NULL ACL.
+ * \param acl_list List of remotes from configuration.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ENOMEM on failed memory allocation.
+ */
+static int zones_set_acl(acl_t **acl, list* acl_list)
+{
+ if (!acl || !acl_list) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Truncate old ACL. */
+ acl_delete(acl);
+
+ /* Create new ACL. */
+ *acl = acl_new(ACL_DENY, 0);
+ if (!*acl) {
+ return KNOTD_ENOMEM;
+ }
+
+ /* Load ACL rules. */
+ conf_remote_t *r = 0;
+ WALK_LIST(r, *acl_list) {
+
+ /* Initialize address. */
+ /*! Port matching disabled, port = 0. */
+ sockaddr_t addr;
+ conf_iface_t *cfg_if = r->remote;
+ int ret = sockaddr_set(&addr, cfg_if->family,
+ cfg_if->address, 0);
+
+ /* Load rule. */
+ if (ret > 0) {
+ acl_create(*acl, &addr, ACL_ACCEPT);
+ }
+ }
+
+ return KNOTD_EOK;
+}
+
+/*!
+ * \brief Load zone to zone database.
+ *
+ * \param zonedb Zone database to load the zone into.
+ * \param zone_name Zone name (owner of the apex node).
+ * \param source Path to zone file source.
+ * \param filename Path to requested compiled zone file.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_EINVAL
+ * \retval KNOTD_EZONEINVAL
+ */
+static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name,
+ const char *source, const char *filename)
+{
+ knot_zone_t *zone = NULL;
+
+ /* Check path */
+ if (filename) {
+ dbg_zones("zones: parsing zone database '%s'\n", filename);
+ zloader_t *zl = 0;
+ int ret = knot_zload_open(&zl, filename);
+ switch(ret) {
+ case KNOT_EOK:
+ /* OK */
+ break;
+ case KNOT_EFEWDATA:
+ log_server_error("Compiled zone db '%s' not exists.\n",
+ filename);
+ return KNOTD_EZONEINVAL;
+ case KNOT_ECRC:
+ log_server_error("Compiled zone db CRC mismatches, "
+ "db is corrupted or .crc file is "
+ "deleted.\n");
+ return KNOTD_EZONEINVAL;
+ case KNOT_EMALF:
+ log_server_error("Compiled db '%s' is too old, "
+ " please recompile.\n",
+ filename);
+ return KNOTD_EZONEINVAL;
+ case KNOT_ERROR:
+ case KNOT_ENOMEM:
+ default:
+ log_server_error("Failed to read zone db file '%s'.\n",
+ filename);
+ return KNOTD_EZONEINVAL;
+ }
+
+ /* Check if the db is up-to-date */
+ int src_changed = strcmp(source, zl->source) != 0;
+ if (src_changed || knot_zload_needs_update(zl)) {
+ log_server_warning("Database for zone '%s' is not "
+ "up-to-date. Please recompile.\n",
+ zone_name);
+ }
+
+ zone = knot_zload_load(zl);
+
+ /* Check loaded name. */
+ const knot_dname_t *dname = knot_zone_name(zone);
+ knot_dname_t *dname_req = 0;
+ dname_req = knot_dname_new_from_str(zone_name,
+ strlen(zone_name), 0);
+ if (knot_dname_compare(dname, dname_req) != 0) {
+ log_server_warning("Origin of the zone db file is "
+ "different than '%s'\n",
+ zone_name);
+ knot_zone_deep_free(&zone, 0);
+ zone = 0;
+
+ }
+ knot_dname_free(&dname_req);
+
+ /* CLEANUP */
+ //knot_zone_contents_dump(zone->contents, 1);
+
+ if (zone) {
+ /* save the timestamp from the zone db file */
+ struct stat s;
+ stat(filename, &s);
+ knot_zone_set_version(zone, s.st_mtime);
+
+ if (knot_zonedb_add_zone(zonedb, zone) != 0){
+ knot_zone_deep_free(&zone, 0);
+ zone = 0;
+ }
+ }
+
+ knot_zload_close(zl);
+
+ if (!zone) {
+ log_server_error("Failed to load "
+ "db '%s' for zone '%s'.\n",
+ filename, zone_name);
+ return KNOTD_EZONEINVAL;
+ }
+ } else {
+ /* db is null. */
+ return KNOTD_EINVAL;
+ }
+
+ /* CLEANUP */
+// knot_zone_dump(zone, 1);
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Return 'serial_from' part of the key. */
+static inline uint32_t ixfrdb_key_from(uint64_t k)
+{
+ /* 64 32 0
+ * key = [TO | FROM]
+ * Need: Least significant 32 bits.
+ */
+ return (uint32_t)(k & ((uint64_t)0x00000000ffffffff));
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Return 'serial_to' part of the key. */
+static inline uint32_t ixfrdb_key_to(uint64_t k)
+{
+ /* 64 32 0
+ * key = [TO | FROM]
+ * Need: Most significant 32 bits.
+ */
+ return (uint32_t)(k >> (uint64_t)32);
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Compare function to match entries with target serial. */
+static inline int ixfrdb_key_to_cmp(uint64_t k, uint64_t to)
+{
+ /* 64 32 0
+ * key = [TO | FROM]
+ * Need: Most significant 32 bits.
+ */
+ return ((uint64_t)ixfrdb_key_to(k)) - to;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Compare function to match entries with starting serial. */
+static inline int ixfrdb_key_from_cmp(uint64_t k, uint64_t from)
+{
+ /* 64 32 0
+ * key = [TO | FROM]
+ * Need: Least significant 32 bits.
+ */
+ return ((uint64_t)ixfrdb_key_from(k)) - from;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Make key for journal from serials. */
+static inline uint64_t ixfrdb_key_make(uint32_t from, uint32_t to)
+{
+ /* 64 32 0
+ * key = [TO | FROM]
+ */
+ return (((uint64_t)to) << ((uint64_t)32)) | ((uint64_t)from);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int zones_changesets_from_binary(knot_changesets_t *chgsets)
+{
+ assert(chgsets != NULL);
+ assert(chgsets->allocated >= chgsets->count);
+ /*
+ * Parses changesets from the binary format stored in chgsets->data
+ * into the changeset_t structures.
+ */
+ knot_rrset_t *rrset = 0;
+ int ret = 0;
+
+ for (int i = 0; i < chgsets->count; ++i) {
+
+ /* Read initial changeset RRSet - SOA. */
+ knot_changeset_t* chs = chgsets->sets + i;
+ size_t remaining = chs->size;
+ ret = knot_zload_rrset_deserialize(&rrset, chs->data, &remaining);
+ if (ret != KNOT_EOK) {
+ dbg_xfr("xfr: SOA: failed to deserialize data "
+ "from changeset, %s\n", knot_strerror(ret));
+ return KNOTD_EMALF;
+ }
+
+ /* in this special case (changesets loaded
+ * from journal) the SOA serial should already
+ * be set, check it.
+ */
+ assert(knot_rrset_type(rrset) == KNOT_RRTYPE_SOA);
+ assert(chs->serial_from ==
+ knot_rdata_soa_serial(knot_rrset_rdata(rrset)));
+ knot_changeset_store_soa(&chs->soa_from, &chs->serial_from,
+ rrset);
+
+ dbg_xfr_verb("xfr: reading RRSets to REMOVE\n");
+
+ /* Read remaining RRSets */
+ int in_remove_section = 1;
+ while (remaining > 0) {
+
+ /* Parse next RRSet. */
+ rrset = 0;
+ uint8_t *stream = chs->data + (chs->size - remaining);
+ ret = knot_zload_rrset_deserialize(&rrset, stream, &remaining);
+ if (ret != KNOT_EOK) {
+ dbg_xfr("xfr: failed to deserialize data "
+ "from changeset, %s\n",
+ knot_strerror(ret));
+ return KNOTD_EMALF;
+ }
+
+ /* Check for next SOA. */
+ if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) {
+
+ /* Move to ADD section if in REMOVE. */
+ if (in_remove_section) {
+ knot_changeset_store_soa(
+ &chgsets->sets[i].soa_to,
+ &chgsets->sets[i].serial_to,
+ rrset);
+ dbg_xfr_verb("xfr: reading RRSets"
+ " to ADD\n");
+ in_remove_section = 0;
+ } else {
+ /* Final SOA. */
+ dbg_xfr_verb("xfr: extra SOA\n");
+ knot_rrset_free(&rrset);
+ break;
+ }
+ } else {
+ /* Remove RRSets. */
+ if (in_remove_section) {
+ ret = knot_changeset_add_rrset(
+ &chgsets->sets[i].remove,
+ &chgsets->sets[i].remove_count,
+ &chgsets->sets[i]
+ .remove_allocated,
+ rrset);
+ } else {
+ /* Add RRSets. */
+ ret = knot_changeset_add_rrset(
+ &chgsets->sets[i].add,
+ &chgsets->sets[i].add_count,
+ &chgsets->sets[i].add_allocated,
+ rrset);
+ }
+
+ /* Check result. */
+ if (ret != KNOT_EOK) {
+ dbg_xfr("xfr: failed to add/remove "
+ "RRSet to changeset: %s\n",
+ knot_strerror(ret));
+ return KNOTD_ERROR;
+ }
+ }
+ }
+
+ dbg_xfr_verb("xfr: read all RRSets in changeset\n");
+ }
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int zones_load_changesets(const knot_zone_t *zone,
+ knot_changesets_t *dst,
+ uint32_t from, uint32_t to)
+{
+ if (!zone || !dst) {
+ dbg_zones_detail("Bad arguments: zone=%p, dst=%p\n", zone, dst);
+ return KNOTD_EINVAL;
+ }
+ if (!zone->data) {
+ dbg_zones_detail("Bad arguments: zone->data=%p\n", zone->data);
+ return KNOTD_EINVAL;
+ }
+
+ dbg_xfr("Loading changesets from serial %u to %u\n", from, to);
+
+ /* Fetch zone-specific data. */
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ if (!zd->ixfr_db) {
+ dbg_zones_detail("Bad arguments: zd->ixfr_db=%p\n", zone->data);
+ return KNOTD_EINVAL;
+ }
+
+ /* Read entries from starting serial until finished. */
+ uint32_t found_to = from;
+ journal_node_t *n = 0;
+ int ret = journal_fetch(zd->ixfr_db, from, ixfrdb_key_from_cmp, &n);
+ if (ret != KNOTD_EOK) {
+ dbg_xfr("xfr: failed to fetch starting changeset: %s\n",
+ knotd_strerror(ret));
+ return ret;
+ }
+
+ while (n != 0 && n != journal_end(zd->ixfr_db)) {
+
+ /* Check for history end. */
+ if (to == found_to) {
+ break;
+ }
+
+ /*! \todo Increment and decrement to reserve +1,
+ * but not incremented counter.*/
+ /* Check changesets size if needed. */
+ ++dst->count;
+ ret = knot_changesets_check_size(dst);
+ --dst->count;
+ if (ret != KNOT_EOK) {
+ --dst->count;
+ dbg_xfr("xfr: failed to check changesets size: %s\n",
+ knot_strerror(ret));
+ return KNOTD_ERROR;
+ }
+
+ /* Initialize changeset. */
+ dbg_xfr_detail("xfr: reading entry #%zu id=%llu\n",
+ dst->count, (unsigned long long)n->id);
+ knot_changeset_t *chs = dst->sets + dst->count;
+ chs->serial_from = ixfrdb_key_from(n->id);
+ chs->serial_to = ixfrdb_key_to(n->id);
+ chs->data = malloc(n->len);
+ if (!chs->data) {
+ return KNOTD_ENOMEM;
+ }
+
+ /* Read journal entry. */
+ ret = journal_read(zd->ixfr_db, n->id,
+ 0, (char*)chs->data);
+ if (ret != KNOTD_EOK) {
+ dbg_xfr("xfr: failed to read data from journal\n");
+ free(chs->data);
+ return KNOTD_ERROR;
+ }
+
+ /* Update changeset binary size. */
+ chs->size = chs->allocated = n->len;
+
+ /* Next node. */
+ found_to = chs->serial_to;
+ ++dst->count;
+ ++n;
+
+ /*! \todo Check consistency. */
+ }
+
+ dbg_xfr_detail("xfr: Journal entries read.\n");
+
+ /* Unpack binary data. */
+ ret = zones_changesets_from_binary(dst);
+ if (ret != KNOT_EOK) {
+ dbg_xfr("xfr: failed to unpack changesets "
+ "from binary, %s\n", knot_strerror(ret));
+ return KNOTD_ERROR;
+ }
+
+ /* Check for complete history. */
+ if (to != found_to) {
+ dbg_xfr_detail("Returning ERANGE\n");
+ return KNOTD_ERANGE;
+ }
+
+ /* History reconstructed. */
+ dbg_xfr_detail("Returning EOK\n");
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Apply changesets to zone from journal.
+ *
+ * \param zone Specified zone.
+ *
+ * \retval KNOTD_EOK if successful.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ENOENT if zone has no contents.
+ * \retval KNOTD_ERROR on unspecified error.
+ */
+static int zones_journal_apply(knot_zone_t *zone)
+{
+ /* Fetch zone. */
+ if (!zone) {
+ return KNOTD_EINVAL;
+ }
+
+ knot_zone_contents_t *contents = knot_zone_get_contents(zone);
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ if (!contents || !zd) {
+ return KNOTD_ENOENT;
+ }
+
+ /* Fetch SOA serial. */
+ const knot_rrset_t *soa_rrs = 0;
+ const knot_rdata_t *soa_rr = 0;
+ soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA);
+ soa_rr = knot_rrset_rdata(soa_rrs);
+ int64_t serial_ret = knot_rdata_soa_serial(soa_rr);
+ if (serial_ret < 0) {
+ return KNOTD_EINVAL;
+ }
+ uint32_t serial = (uint32_t)serial_ret;
+
+ /* Load all pending changesets. */
+ dbg_zones_verb("zones: loading all changesets of '%s' from SERIAL %u\n",
+ zd->conf->name, serial);
+ knot_changesets_t* chsets = malloc(sizeof(knot_changesets_t));
+ memset(chsets, 0, sizeof(knot_changesets_t));
+ /*! \todo Check what should be the upper bound. */
+ int ret = zones_load_changesets(zone, chsets, serial, serial - 1);
+ if (ret == KNOTD_EOK || ret == KNOTD_ERANGE) {
+ if (chsets->count > 0) {
+ /* Apply changesets. */
+ log_server_info("Applying '%zu' changesets from journal "
+ "to zone '%s'.\n",
+ chsets->count, zd->conf->name);
+ ret = xfrin_apply_changesets_to_zone(zone, chsets);
+ if (ret != KNOT_EOK) {
+ log_server_error("Failed to apply changesets to "
+ "'%s' - %s\n",
+ zd->conf->name,
+ knot_strerror(ret));
+ ret = KNOTD_ERROR;
+ }
+ }
+ } else {
+ dbg_zones("zones: failed to load changesets - %s\n",
+ knotd_strerror(ret));
+ }
+
+ /* Free changesets and return. */
+ knot_free_changesets(&chsets);
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Fill the new database with zones.
+ *
+ * Zones that should be retained are just added from the old database to the
+ * new. New zones are loaded.
+ *
+ * \param ns Name server instance.
+ * \param zone_conf Zone configuration.
+ * \param db_old Old zone database.
+ * \param db_new New zone database.
+ *
+ * \return Number of inserted zones.
+ */
+static int zones_insert_zones(knot_nameserver_t *ns,
+ const list *zone_conf,
+ const knot_zonedb_t *db_old,
+ knot_zonedb_t *db_new)
+{
+ /*! \todo Change to zone contents. */
+
+ node *n = 0;
+ int inserted = 0;
+ /* for all zones in the configuration */
+ WALK_LIST(n, *zone_conf) {
+ conf_zone_t *z = (conf_zone_t *)n;
+
+ /* Convert the zone name into a domain name. */
+ /* Local allocation, will be discarded. */
+ knot_dname_t *zone_name = knot_dname_new_from_str(z->name,
+ strlen(z->name), NULL);
+ if (zone_name == NULL) {
+ log_server_error("Error creating domain name from zone"
+ " name\n");
+ return inserted;
+ }
+
+ dbg_zones_verb("zones: inserting zone %s into the new database.\n",
+ z->name);
+
+ /* try to find the zone in the current zone db */
+ knot_zone_t *zone = knot_zonedb_find_zone(db_old,
+ zone_name);
+ int reload = 0;
+
+ /* Attempt to bootstrap if db or source does not exist. */
+ struct stat s;
+ int stat_ret = stat(z->file, &s);
+ if (zone != NULL) {
+ /* if found, check timestamp of the file against the
+ * loaded zone
+ */
+ if (knot_zone_version(zone) < s.st_mtime) {
+ /* the file is newer, reload! */
+ reload = 1;
+ }
+ } else {
+ reload = 1;
+ }
+
+ /* Reload zone file. */
+ int ret = KNOTD_ERROR;
+ if (reload) {
+ /* Zone file not exists and has master set. */
+ if (stat_ret < 0 && !EMPTY_LIST(z->acl.xfr_in)) {
+
+ /* Create stub database. */
+ dbg_zones_verb("zones: loading stub zone '%s' "
+ "for bootstrap.\n",
+ z->name);
+ knot_dname_t *owner = 0;
+ owner = knot_dname_deep_copy(zone_name);
+ knot_zone_t* sz = knot_zone_new_empty(owner);
+ if (sz) {
+ /* Add stub zone to db_new. */
+ ret = knot_zonedb_add_zone(db_new, sz);
+ if (ret != KNOT_EOK) {
+ dbg_zones("zones: failed to add "
+ "stub zone '%s'.\n",
+ z->name);
+ knot_zone_deep_free(&sz, 0);
+ sz = 0;
+ ret = KNOTD_ERROR;
+ } else {
+ log_server_info("Will attempt to "
+ "bootstrap zone "
+ "%s from AXFR "
+ "master.\n",
+ z->name);
+ --inserted;
+ }
+
+ } else {
+ dbg_zones("zones: failed to create "
+ "stub zone '%s'.\n",
+ z->name);
+ ret = KNOTD_ERROR;
+ }
+
+ } else {
+ dbg_zones_verb("zones: loading zone '%s' "
+ "from '%s'\n",
+ z->name,
+ z->db);
+ ret = zones_load_zone(db_new, z->name,
+ z->file, z->db);
+ if (ret == KNOTD_EOK) {
+ log_server_info("Loaded zone '%s'\n",
+ z->name);
+ } else {
+ log_server_error("Failed to load zone "
+ "'%s' - %s\n",
+ z->name,
+ knotd_strerror(ret));
+ }
+ }
+
+ /* Find zone. */
+ if (ret == KNOTD_EOK) {
+ /* Find the new zone */
+ zone = knot_zonedb_find_zone(db_new,
+ zone_name);
+ ++inserted;
+
+ dbg_zones_verb("zones: inserted '%s' into "
+ "database, initializing data\n",
+ z->name);
+
+ /* Initialize zone-related data. */
+ zonedata_init(z, zone);
+
+ }
+ /* unused return value, if not loaded, just continue */
+ } else {
+ /* just insert the zone into the new zone db */
+ dbg_zones_verb("zones: found '%s' in old database, "
+ "copying to new.\n",
+ z->name);
+ log_server_info("Zone '%s' is up-to-date, no need "
+ "for reload.\n", z->name);
+ int ret = knot_zonedb_add_zone(db_new, zone);
+ if (ret != KNOT_EOK) {
+ log_server_error("Error adding known zone '%s' to"
+ " the new database - %s\n",
+ z->name, knot_strerror(ret));
+ ret = KNOTD_ERROR;
+ } else {
+ ++inserted;
+ }
+ }
+
+ /* Update zone data. */
+ if (zone) {
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+
+ /* Update refs. */
+ zd->conf = z;
+
+ /* Update ACLs. */
+ dbg_zones("Updating zone ACLs.\n");
+ zones_set_acl(&zd->xfr_in.acl, &z->acl.xfr_in);
+ zones_set_acl(&zd->xfr_out, &z->acl.xfr_out);
+ zones_set_acl(&zd->notify_in, &z->acl.notify_in);
+ zones_set_acl(&zd->notify_out, &z->acl.notify_out);
+
+ /* Update server pointer. */
+ zd->server = (server_t *)knot_ns_get_data(ns);
+
+ /* Update master server address. */
+ memset(&zd->xfr_in.tsig_key, 0, sizeof(knot_key_t));
+ sockaddr_init(&zd->xfr_in.master, -1);
+ if (!EMPTY_LIST(z->acl.xfr_in)) {
+ conf_remote_t *r = HEAD(z->acl.xfr_in);
+ conf_iface_t *cfg_if = r->remote;
+ sockaddr_set(&zd->xfr_in.master,
+ cfg_if->family,
+ cfg_if->address,
+ cfg_if->port);
+ /*!< \todo [TSIG] DISABLED */
+// if (cfg_if->key) {
+// memcpy(&zd->xfr_in.tsig_key,
+// cfg_if->key,
+// sizeof(knot_key_t));
+// }
+
+ dbg_zones("zones: using %s:%d as XFR master "
+ "for '%s'\n",
+ cfg_if->address,
+ cfg_if->port,
+ z->name);
+ }
+
+ /* Apply changesets from journal. */
+ zones_journal_apply(zone);
+
+ /* Update events scheduled for zone. */
+ zones_timers_update(zone, z,
+ ((server_t *)knot_ns_get_data(ns))->sched);
+ }
+
+ /* CLEANUP */
+// knot_zone_contents_dump(knot_zone_get_contents(zone), 1);
+
+ /* Directly discard zone. */
+ knot_dname_free(&zone_name);
+ }
+ return inserted;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Remove zones present in the configuration from the old database.
+ *
+ * After calling this function, the old zone database should contain only zones
+ * that should be completely deleted.
+ *
+ * \param zone_conf Zone configuration.
+ * \param db_old Old zone database to remove zones from.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_ERROR
+ */
+static int zones_remove_zones(const knot_zonedb_t *db_new,
+ knot_zonedb_t *db_old)
+{
+ const knot_zone_t **new_zones = knot_zonedb_zones(db_new);
+ if (new_zones == NULL) {
+ return KNOTD_ENOMEM;
+ }
+
+ for (int i = 0; i < knot_zonedb_zone_count(db_new); ++i) {
+ /* try to find the new zone in the old DB
+ * if the pointers match, remove the zone from old DB
+ */
+ /*! \todo Find better way of removing zone with given pointer.*/
+ knot_zone_t *old_zone = knot_zonedb_find_zone(
+ db_old, knot_zone_name(new_zones[i]));
+ if (old_zone == new_zones[i]) {
+dbg_zones_exec(
+ char *name = knot_dname_to_str(knot_zone_name(old_zone));
+ dbg_zones_verb("zones: zone pointers match, removing zone %s "
+ "from database.\n", name);
+ free(name);
+);
+ knot_zone_t * rm = knot_zonedb_remove_zone(db_old,
+ knot_zone_name(old_zone));
+ assert(rm == old_zone);
+ }
+ }
+
+ free(new_zones);
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns,
+ knot_zonedb_t **db_old)
+{
+ /* Check parameters */
+ if (conf == NULL || ns == NULL) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Lock RCU to ensure none will deallocate any data under our hands. */
+ rcu_read_lock();
+
+ /* Grab a pointer to the old database */
+ *db_old = ns->zone_db;
+ if (*db_old == NULL) {
+ log_server_error("Missing zone database in nameserver structure"
+ ".\n");
+ return KNOTD_ERROR;
+ }
+
+ /* Create new zone DB */
+ knot_zonedb_t *db_new = knot_zonedb_new();
+ if (db_new == NULL) {
+ return KNOTD_ERROR;
+ }
+
+ log_server_info("Loading %d compiled zones...\n", conf->zones_count);
+
+ /* Insert all required zones to the new zone DB. */
+ int inserted = zones_insert_zones(ns, &conf->zones, *db_old, db_new);
+
+ log_server_info("Loaded %d out of %d zones.\n", inserted,
+ conf->zones_count);
+
+ if (inserted != conf->zones_count) {
+ log_server_warning("Not all the zones were loaded.\n");
+ }
+
+ dbg_zones_detail("zones: old db in nameserver: %p, old db stored: %p, new db: %p\n",
+ ns->zone_db, *db_old, db_new);
+
+ /* Switch the databases. */
+ (void)rcu_xchg_pointer(&ns->zone_db, db_new);
+
+ dbg_zones_detail("db in nameserver: %p, old db stored: %p, new db: %p\n",
+ ns->zone_db, *db_old, db_new);
+
+ /*
+ * Remove all zones present in the new DB from the old DB.
+ * No new thread can access these zones in the old DB, as the
+ * databases are already switched.
+ *
+ * Beware - only the exact same zones (same pointer) may be removed.
+ * All other have been loaded again so that the old must be destroyed.
+ */
+ int ret = zones_remove_zones(db_new, *db_old);
+ if (ret != KNOTD_EOK) {
+ return ret;
+ }
+
+ /* Unlock RCU, messing with any data will not affect us now */
+ rcu_read_unlock();
+
+ return KNOTD_EOK;
+}
+
+int zones_zonefile_sync(knot_zone_t *zone)
+{
+ if (!zone) {
+ return KNOTD_EINVAL;
+ }
+ if (!zone->data) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Fetch zone data. */
+ zonedata_t *zd = (zonedata_t *)zone->data;
+
+ /* Lock zone data. */
+ pthread_mutex_lock(&zd->lock);
+
+ knot_zone_contents_t *contents = knot_zone_get_contents(zone);
+ if (!contents) {
+ pthread_mutex_unlock(&zd->lock);
+ return KNOTD_EINVAL;
+ }
+
+ /* Latest zone serial. */
+ const knot_rrset_t *soa_rrs = 0;
+ const knot_rdata_t *soa_rr = 0;
+ soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA);
+ soa_rr = knot_rrset_rdata(soa_rrs);
+ int64_t serial_ret = knot_rdata_soa_serial(soa_rr);
+ if (serial_ret < 0) {
+ return KNOTD_EINVAL;
+ }
+ uint32_t serial_to = (uint32_t)serial_ret;
+
+ /* Check for difference against zonefile serial. */
+ if (zd->zonefile_serial != serial_to) {
+
+ /* Save zone to zonefile. */
+ conf_read_lock();
+ dbg_zones("zones: syncing '%s' differences to '%s' "
+ "(SOA serial %u)\n",
+ zd->conf->name, zd->conf->file, serial_to);
+ zone_dump_text(contents, zd->conf->file);
+ conf_read_unlock();
+
+ /* Update journal entries. */
+ dbg_zones_verb("zones: unmarking all dirty nodes "
+ "in '%s' journal\n",
+ zd->conf->name);
+ journal_walk(zd->ixfr_db, zones_ixfrdb_sync_apply);
+
+ /* Update zone file serial. */
+ dbg_zones("zones: new '%s' zonefile serial is %u\n",
+ zd->conf->name, serial_to);
+ zd->zonefile_serial = serial_to;
+ } else {
+ dbg_zones_verb("zones: '%s' zonefile is in sync "
+ "with differences\n", zd->conf->name);
+ }
+
+ /* Unlock zone data. */
+ pthread_mutex_unlock(&zd->lock);
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int zones_xfr_check_zone(knot_ns_xfr_t *xfr, knot_rcode_t *rcode)
+{
+ if (xfr == NULL || rcode == NULL) {
+ *rcode = KNOT_RCODE_SERVFAIL;
+ return KNOTD_EINVAL;
+ }
+
+ /* Check if the zone is found. */
+ if (xfr->zone == NULL) {
+ *rcode = KNOT_RCODE_REFUSED;
+ return KNOTD_EACCES;
+ }
+
+ /* Check zone data. */
+ zonedata_t *zd = (zonedata_t *)xfr->zone->data;
+ if (zd == NULL) {
+ dbg_zones("zones: invalid zone data for zone %p\n", xfr->zone);
+ *rcode = KNOT_RCODE_SERVFAIL;
+ return KNOTD_ERROR;
+ }
+
+ /* Check zone contents. */
+ if (knot_zone_contents(xfr->zone) == NULL) {
+ dbg_zones("zones: invalid zone contents for zone %p\n", xfr->zone);
+ *rcode = KNOT_RCODE_SERVFAIL;
+ return KNOTD_EEXPIRED;
+ }
+
+ // Check xfr-out ACL
+ if (acl_match(zd->xfr_out, &xfr->addr) == ACL_DENY) {
+ log_answer_warning("Unauthorized request for XFR '%s/OUT'.\n",
+ zd->conf->name);
+ *rcode = KNOT_RCODE_REFUSED;
+ return KNOTD_EACCES;
+ } else {
+ dbg_zones("zones: authorized XFR '%s/OUT'\n",
+ zd->conf->name);
+ }
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int zones_process_response(knot_nameserver_t *nameserver,
+ sockaddr_t *from,
+ knot_packet_t *packet, uint8_t *response_wire,
+ size_t *rsize)
+{
+ if (!packet || !rsize || nameserver == NULL || from == NULL ||
+ response_wire == NULL) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Handle SOA query response, cancel EXPIRE timer
+ * and start AXFR transfer if needed.
+ * Reset REFRESH timer on finish.
+ */
+ if (knot_packet_qtype(packet) == KNOT_RRTYPE_SOA) {
+
+ if (knot_packet_rcode(packet) != KNOT_RCODE_NOERROR) {
+ /*! \todo Handle error response. */
+ return KNOTD_ERROR;
+ }
+
+ /* No response. */
+ *rsize = 0;
+
+ /* Find matching zone and ID. */
+ const knot_dname_t *zone_name = knot_packet_qname(packet);
+ /*! \todo Change the access to the zone db. */
+ knot_zone_t *zone = knot_zonedb_find_zone(
+ nameserver->zone_db,
+ zone_name);
+
+ /* Get zone contents. */
+ rcu_read_lock();
+ const knot_zone_contents_t *contents =
+ knot_zone_contents(zone);
+
+ if (!zone || !knot_zone_data(zone) || !contents) {
+ rcu_read_unlock();
+ return KNOTD_EINVAL;
+ }
+
+ /* Match ID against awaited. */
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ uint16_t pkt_id = knot_packet_id(packet);
+ if ((int)pkt_id != zd->xfr_in.next_id) {
+ rcu_read_unlock();
+ return KNOTD_ERROR;
+ }
+
+ /* Check SOA SERIAL. */
+ int ret = xfrin_transfer_needed(contents, packet);
+ dbg_zones_verb("xfrin_transfer_needed() returned %d\n", ret);
+ if (ret < 0) {
+ /* RETRY/EXPIRE timers running, do not interfere. */
+ return KNOTD_ERROR;
+ }
+
+ /* No updates available. */
+ evsched_t *sched =
+ ((server_t *)knot_ns_get_data(nameserver))->sched;
+ if (ret == 0) {
+ log_zone_info("SOA query for zone '%s' answered, no "
+ "transfer needed.\n", zd->conf->name);
+ rcu_read_unlock();
+
+ /* Reinstall timers. */
+ zones_timers_update(zone, zd->conf, sched);
+ return KNOTD_EOK;
+ }
+
+ assert(ret > 0);
+
+ /* Already transferring. */
+ if (pthread_mutex_trylock(&zd->xfr_in.lock) != 0) {
+ /* Unlock zone contents. */
+ dbg_zones("zones: SOA response received, but zone is "
+ "being transferred, refusing to start another "
+ "transfer\n");
+ rcu_read_unlock();
+ return KNOTD_EOK;
+ } else {
+ pthread_mutex_unlock(&zd->xfr_in.lock);
+ }
+
+ /* Prepare XFR client transfer. */
+ knot_ns_xfr_t xfr_req;
+ memset(&xfr_req, 0, sizeof(knot_ns_xfr_t));
+ memcpy(&xfr_req.addr, from, sizeof(sockaddr_t));
+ xfr_req.zone = (void *)zone;
+ xfr_req.send = zones_send_cb;
+
+ /* Select transfer method. */
+ xfr_req.type = zones_transfer_to_use(contents);
+
+ /* Select TSIG key. */
+ /*!< \todo [TSIG] DISABLED */
+ xfr_req.tsig_key = 0;
+ /* CLEANUP */
+// if (zd->xfr_in.tsig_key.name) {
+// xfr_req.tsig_key = &zd->xfr_in.tsig_key;
+// }
+
+ /* Unlock zone contents. */
+ rcu_read_unlock();
+
+ /* Enqueue XFR request. */
+ return xfr_request(((server_t *)knot_ns_get_data(
+ nameserver))->xfr_h, &xfr_req);
+ }
+
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_ns_xfr_type_t zones_transfer_to_use(const knot_zone_contents_t *zone)
+{
+ /*! \todo Implement. */
+ return XFR_TYPE_IIN;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int zones_find_zone_for_xfr(const knot_zone_contents_t *zone,
+ const char **zonefile, const char **zonedb)
+{
+ /* find the zone file name and zone db file name for the zone */
+ conf_t *cnf = conf();
+ node *n = NULL;
+ WALK_LIST(n, cnf->zones) {
+ conf_zone_t *zone_conf = (conf_zone_t *)n;
+ knot_dname_t *zone_name = knot_dname_new_from_str(
+ zone_conf->name, strlen(zone_conf->name), NULL);
+ if (zone_name == NULL) {
+ return KNOTD_ENOMEM;
+ }
+
+ int r = knot_dname_compare(zone_name, knot_node_owner(
+ knot_zone_contents_apex(zone)));
+
+ /* Directly discard dname, won't be needed. */
+ knot_dname_free(&zone_name);
+
+ if (r == 0) {
+ /* found the right zone */
+ *zonefile = zone_conf->file;
+ *zonedb = zone_conf->db;
+ return KNOTD_EOK;
+ }
+ }
+
+ char *name = knot_dname_to_str(knot_node_owner(
+ knot_zone_contents_apex(zone)));
+ dbg_zones("zones: no zone found for the zone received by transfer "
+ "(%s).\n", name);
+ free(name);
+
+ return KNOTD_ENOENT;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static char *zones_find_free_filename(const char *old_name)
+{
+ /* find zone name not present on the disk */
+ int free_name = 0;
+ size_t name_size = strlen(old_name);
+
+ char *new_name = malloc(name_size + 3);
+ if (new_name == NULL) {
+ return NULL;
+ }
+ memcpy(new_name, old_name, name_size);
+ new_name[name_size] = '.';
+ new_name[name_size + 2] = 0;
+
+ dbg_zones_verb("zones: finding free name for the zone file.\n");
+ int c = 48;
+ FILE *file;
+ while (!free_name && c < 58) {
+ new_name[name_size + 1] = c;
+ dbg_zones_verb("zones: trying file name %s\n", new_name);
+ if ((file = fopen(new_name, "r")) != NULL) {
+ fclose(file);
+ ++c;
+ } else {
+ free_name = 1;
+ }
+ }
+
+ if (free_name) {
+ return new_name;
+ } else {
+ free(new_name);
+ return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int zones_dump_xfr_zone_text(knot_zone_contents_t *zone,
+ const char *zonefile)
+{
+ assert(zone != NULL && zonefile != NULL);
+
+ /*! \todo new_zonefile may be created by another process,
+ * until the zone_dump_text is called. Needs to be opened in
+ * this function for writing.
+ * Use open() for exclusive open and fcntl() for locking.
+ */
+
+ char *new_zonefile = zones_find_free_filename(zonefile);
+
+ if (new_zonefile == NULL) {
+ dbg_zones("zones: failed to find free filename for temporary "
+ "storage of the zone text file.\n");
+ return KNOTD_ERROR; /*! \todo New error code? */
+ }
+
+ int rc = zone_dump_text(zone, new_zonefile);
+
+ if (rc != KNOTD_EOK) {
+ dbg_zones("Failed to save the zone to text zone file '%s'.\n",
+ new_zonefile);
+ free(new_zonefile);
+ return KNOTD_ERROR;
+ }
+
+ /*! \todo this would also need locking as well. */
+ struct stat s;
+ rc = stat(zonefile, &s);
+ if (rc < 0 || remove(zonefile) == 0) {
+ if (rename(new_zonefile, zonefile) != 0) {
+ dbg_zones("Failed to replace old zonefile '%s'' with new"
+ " zone file '%s'.\n", zonefile, new_zonefile);
+ /*! \todo with proper locking, this shouldn't happen,
+ * revise it later on.
+ */
+ zone_dump_text(zone, zonefile);
+ return KNOTD_ERROR;
+ }
+ } else {
+ dbg_zones("zones: failed to replace old zonefile '%s'.\n",
+ zonefile);
+ return KNOTD_ERROR;
+ }
+
+ free(new_zonefile);
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ns_dump_xfr_zone_binary(knot_zone_contents_t *zone,
+ const char *zonedb,
+ const char *zonefile)
+{
+ assert(zone != NULL && zonedb != NULL);
+
+ /*! \todo new_zonedb may be created by another process,
+ * until the zone_dump_text is called. Needs to be opened in
+ * this function for writing.
+ * Use open() for exclusive open and fcntl() for locking.
+ */
+ char *new_zonedb = zones_find_free_filename(zonedb);
+
+ if (new_zonedb == NULL) {
+ dbg_zones("zones: failed to find free filename for temporary "
+ "storage of the zone binary file '%s'\n",
+ zonedb);
+ return KNOTD_ERROR; /*! \todo New error code? */
+ }
+
+ /*! \todo this would also need locking as well. */
+ int rc = knot_zdump_dump_and_swap(zone, new_zonedb, zonedb, zonefile);
+ free(new_zonedb);
+
+ if (rc != KNOT_EOK) {
+ return KNOTD_ERROR;
+ }
+
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int zones_save_zone(const knot_ns_xfr_t *xfr)
+{
+ if (xfr == NULL || xfr->data == NULL) {
+ return KNOTD_EINVAL;
+ }
+
+ knot_zone_contents_t *zone =
+ (knot_zone_contents_t *)xfr->data;
+
+ const char *zonefile = NULL;
+ const char *zonedb = NULL;
+
+ int ret = zones_find_zone_for_xfr(zone, &zonefile, &zonedb);
+ if (ret != KNOTD_EOK) {
+ return ret;
+ }
+
+ assert(zonefile != NULL && zonedb != NULL);
+
+ /* dump the zone into text zone file */
+ ret = zones_dump_xfr_zone_text(zone, zonefile);
+ if (ret != KNOTD_EOK) {
+ return KNOTD_ERROR;
+ }
+ /* dump the zone into binary db file */
+ ret = ns_dump_xfr_zone_binary(zone, zonedb, zonefile);
+ if (ret != KNOTD_EOK) {
+ return KNOTD_ERROR;
+ }
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int zones_ns_conf_hook(const struct conf_t *conf, void *data)
+{
+ knot_nameserver_t *ns = (knot_nameserver_t *)data;
+ dbg_zones_verb("zones: reconfiguring name server.\n");
+
+ knot_zonedb_t *old_db = 0;
+
+ int ret = zones_update_db_from_config(conf, ns, &old_db);
+ if (ret != KNOTD_EOK) {
+ return ret;
+ }
+ /* Wait until all readers finish with reading the zones. */
+ synchronize_rcu();
+
+ dbg_zones_verb("zones: nameserver's zone db: %p, old db: %p\n",
+ ns->zone_db, old_db);
+
+ /* Delete all deprecated zones and delete the old database. */
+ knot_zonedb_deep_free(&old_db);
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int zones_check_binary_size(uint8_t **data, size_t *allocated,
+ size_t required)
+{
+ if (required <= *allocated) {
+ return KNOTD_EOK;
+ }
+
+ /* Allocate new memory block. */
+ size_t new_count = required;
+ uint8_t *new_data = malloc(new_count * sizeof(uint8_t));
+ if (new_data == NULL) {
+ return KNOTD_ENOMEM;
+ }
+
+ /* Clear memory block and copy old data. */
+ memset(new_data, 0, new_count * sizeof(uint8_t));
+ memcpy(new_data, *data, *allocated);
+
+ /* Switch pointers and free old pointer. */
+ free(*data);
+ *data = new_data;
+ *allocated = new_count;
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int zones_changeset_rrset_to_binary(uint8_t **data, size_t *size,
+ size_t *allocated,
+ knot_rrset_t *rrset)
+{
+ assert(data != NULL);
+ assert(size != NULL);
+ assert(allocated != NULL);
+
+ /*
+ * In *data, there is the whole changeset in the binary format,
+ * the actual RRSet will be just appended to it
+ */
+
+ uint8_t *binary = NULL;
+ size_t actual_size = 0;
+ int ret = knot_zdump_rrset_serialize(rrset, &binary, &actual_size);
+ if (ret != KNOT_EOK) {
+ return KNOTD_ERROR; /*! \todo Other code? */
+ }
+
+ ret = zones_check_binary_size(data, allocated, *size + actual_size);
+ if (ret != KNOT_EOK) {
+ free(binary);
+ return KNOTD_ERROR;
+ }
+
+ memcpy(*data + *size, binary, actual_size);
+ *size += actual_size;
+ free(binary);
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int zones_changesets_to_binary(knot_changesets_t *chgsets)
+{
+ assert(chgsets != NULL);
+ assert(chgsets->allocated >= chgsets->count);
+
+ /*
+ * Converts changesets to the binary format stored in chgsets->data
+ * from the changeset_t structures.
+ */
+ int ret;
+
+ for (int i = 0; i < chgsets->count; ++i) {
+ knot_changeset_t *ch = &chgsets->sets[i];
+ assert(ch->data == NULL);
+ assert(ch->size == 0);
+
+ /* 1) origin SOA */
+ ret = zones_changeset_rrset_to_binary(&ch->data, &ch->size,
+ &ch->allocated, ch->soa_from);
+ if (ret != KNOT_EOK) {
+ free(ch->data);
+ ch->data = NULL;
+ dbg_zones("zones_changeset_rrset_to_binary(): %s\n",
+ knot_strerror(ret));
+ return KNOTD_ERROR;
+ }
+
+ int j;
+
+ /* 2) remove RRsets */
+ assert(ch->remove_allocated >= ch->remove_count);
+ for (j = 0; j < ch->remove_count; ++j) {
+ ret = zones_changeset_rrset_to_binary(&ch->data,
+ &ch->size,
+ &ch->allocated,
+ ch->remove[j]);
+ if (ret != KNOT_EOK) {
+ free(ch->data);
+ ch->data = NULL;
+ dbg_zones("zones_changeset_rrset_to_binary(): %s\n",
+ knot_strerror(ret));
+ return KNOTD_ERROR;
+ }
+ }
+
+ /* 3) new SOA */
+ ret = zones_changeset_rrset_to_binary(&ch->data, &ch->size,
+ &ch->allocated, ch->soa_to);
+ if (ret != KNOT_EOK) {
+ free(ch->data);
+ ch->data = NULL;
+ dbg_zones("zones_changeset_rrset_to_binary(): %s\n",
+ knot_strerror(ret));
+ return KNOTD_ERROR;
+ }
+
+ /* 4) add RRsets */
+ assert(ch->add_allocated >= ch->add_count);
+ for (j = 0; j < ch->add_count; ++j) {
+ ret = zones_changeset_rrset_to_binary(&ch->data,
+ &ch->size,
+ &ch->allocated,
+ ch->add[j]);
+ if (ret != KNOT_EOK) {
+ free(ch->data);
+ ch->data = NULL;
+ dbg_zones("zones_changeset_rrset_to_binary(): %s\n",
+ knot_strerror(ret));
+ return KNOTD_ERROR;
+ }
+ }
+ }
+
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int zones_store_changesets(knot_ns_xfr_t *xfr)
+{
+ if (xfr == NULL || xfr->data == NULL || xfr->zone == NULL) {
+ return KNOTD_EINVAL;
+ }
+
+ knot_zone_t *zone = xfr->zone;
+ knot_changesets_t *src = (knot_changesets_t *)xfr->data;
+
+ /*! \todo Convert to binary format. */
+
+ int ret = zones_changesets_to_binary(src);
+ if (ret != KNOTD_EOK) {
+ return ret;
+ }
+
+ /* Fetch zone-specific data. */
+ zonedata_t *zd = (zonedata_t *)zone->data;
+ if (!zd->ixfr_db) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Begin writing to journal. */
+ for (unsigned i = 0; i < src->count; ++i) {
+
+ /* Make key from serials. */
+ knot_changeset_t* chs = src->sets + i;
+ uint64_t k = ixfrdb_key_make(chs->serial_from, chs->serial_to);
+
+ /* Write entry. */
+ int ret = journal_write(zd->ixfr_db, k, (const char*)chs->data,
+ chs->size);
+
+ /* Check for errors. */
+ while (ret != KNOTD_EOK) {
+
+ /* Sync to zonefile may be needed. */
+ if (ret == KNOTD_EAGAIN) {
+
+ /* Cancel sync timer. */
+ event_t *tmr = zd->ixfr_dbsync;
+ if (tmr) {
+ dbg_xfr_verb("xfr: cancelling zonefile "
+ "SYNC timer of '%s'\n",
+ zd->conf->name);
+ evsched_cancel(tmr->parent, tmr);
+ }
+
+ /* Synchronize. */
+ dbg_xfr_verb("xfr: forcing zonefile SYNC "
+ "of '%s'\n",
+ zd->conf->name);
+ ret = zones_zonefile_sync(zone);
+ if (ret != KNOTD_EOK) {
+ continue;
+ }
+
+ /* Reschedule sync timer. */
+ if (tmr) {
+ /* Fetch sync timeout. */
+ conf_read_lock();
+ int timeout = zd->conf->dbsync_timeout;
+ timeout *= 1000; /* Convert to ms. */
+ conf_read_unlock();
+
+ /* Reschedule. */
+ dbg_xfr_verb("xfr: resuming SYNC "
+ "of '%s'\n",
+ zd->conf->name);
+ evsched_schedule(tmr->parent, tmr,
+ timeout);
+
+ }
+
+ /* Attempt to write again. */
+ ret = journal_write(zd->ixfr_db, k,
+ (const char*)chs->data,
+ chs->size);
+ } else {
+ /* Other errors. */
+ return KNOTD_ERROR;
+ }
+ }
+
+ /* Free converted binary data. */
+ free(chs->data);
+ chs->data = 0;
+ chs->size = 0;
+ }
+
+ /* Written changesets to journal. */
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from,
+ uint32_t serial_to)
+{
+ if (!xfr || !xfr->zone || !knot_zone_contents(xfr->zone)) {
+ dbg_zones_detail("Wrong parameters: xfr=%p,"
+ " xfr->zone = %p\n", xfr, xfr->zone);
+ return KNOTD_EINVAL;
+ }
+
+ knot_changesets_t *chgsets = (knot_changesets_t *)
+ calloc(1, sizeof(knot_changesets_t));
+ CHECK_ALLOC_LOG(chgsets, KNOTD_ENOMEM);
+
+ int ret = ns_serial_compare(serial_to, serial_from);
+ dbg_zones_verb("Compared serials, result: %d\n", ret);
+
+ /* if serial_to is not larger than serial_from, do not load anything */
+ if (ret <= 0) {
+ xfr->data = chgsets;
+ return KNOTD_EOK;
+ }
+
+ dbg_zones("Loading changesets...\n");
+
+ ret = zones_load_changesets(xfr->zone, chgsets,
+ serial_from, serial_to);
+ if (ret != KNOTD_EOK) {
+ dbg_zones_verb("Loading changesets failed: %s\n",
+ knotd_strerror(ret));
+ return ret;
+ }
+
+ xfr->data = chgsets;
+ return KNOTD_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int zones_apply_changesets(knot_ns_xfr_t *xfr)
+{
+ if (xfr == NULL || xfr->zone == NULL || xfr->data == NULL) {
+ return KNOTD_EINVAL;
+ }
+
+ return xfrin_apply_changesets_to_zone(xfr->zone,
+ (knot_changesets_t *)xfr->data);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch)
+{
+ if (!sch || !zone) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Fetch zone data. */
+ zonedata_t *zd = (zonedata_t *)zone->data;
+ if (!zd) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Cancel REFRESH timer. */
+ if (zd->xfr_in.timer) {
+ evsched_cancel(sch, zd->xfr_in.timer);
+ evsched_event_free(sch, zd->xfr_in.timer);
+ zd->xfr_in.timer = 0;
+ }
+
+ /* Cancel EXPIRE timer. */
+ if (zd->xfr_in.expire) {
+ evsched_cancel(sch, zd->xfr_in.expire);
+ evsched_event_free(sch, zd->xfr_in.expire);
+ zd->xfr_in.expire = 0;
+ }
+
+ /* Remove list of pending NOTIFYs. */
+ pthread_mutex_lock(&zd->lock);
+ notify_ev_t *ev = 0, *evn = 0;
+ WALK_LIST_DELSAFE(ev, evn, zd->notify_pending) {
+ zones_cancel_notify(zd, ev);
+ }
+ pthread_mutex_unlock(&zd->lock);
+
+ /* Check XFR/IN master server. */
+ if (zd->xfr_in.master.ptr) {
+
+ /* Schedule REFRESH timer. */
+ uint32_t refresh_tmr = 0;
+ if (knot_zone_contents(zone)) {
+ refresh_tmr = zones_soa_refresh(zone);
+ } else {
+ refresh_tmr = zd->xfr_in.bootstrap_retry;
+ }
+ zd->xfr_in.timer = evsched_schedule_cb(sch, zones_refresh_ev,
+ zone, refresh_tmr);
+ dbg_zones("zone: REFRESH set to %u\n", refresh_tmr);
+ }
+
+ /* Schedule IXFR database syncing. */
+ /*! \todo Sync timer should not be reset after each xfr. */
+ int sync_timeout = cfzone->dbsync_timeout * 1000; /* Convert to ms. */
+ if (zd->ixfr_dbsync) {
+ evsched_cancel(sch, zd->ixfr_dbsync);
+ evsched_event_free(sch, zd->ixfr_dbsync);
+ zd->ixfr_dbsync = 0;
+ }
+ if (zd->ixfr_db) {
+ zd->ixfr_dbsync = evsched_schedule_cb(sch,
+ zones_zonefile_sync_ev,
+ zone, sync_timeout);
+ }
+
+ /* Do not issue NOTIFY queries if stub. */
+ if (!knot_zone_contents(zone)) {
+ conf_read_unlock();
+ return KNOTD_EOK;
+ }
+
+ /* Schedule NOTIFY to slaves. */
+ conf_remote_t *r = 0;
+ conf_read_lock();
+ WALK_LIST(r, cfzone->acl.notify_out) {
+
+ /* Fetch remote. */
+ conf_iface_t *cfg_if = r->remote;
+
+ /* Create request. */
+ notify_ev_t *ev = malloc(sizeof(notify_ev_t));
+ if (!ev) {
+ free(ev);
+ dbg_zones("notify: out of memory to create "
+ "NOTIFY query for %s\n", cfg_if->name);
+ continue;
+ }
+
+ /* Parse server address. */
+ int ret = sockaddr_set(&ev->addr, cfg_if->family,
+ cfg_if->address,
+ cfg_if->port);
+ if (ret < 1) {
+ free(ev);
+ dbg_zones("notify: NOTIFY slave %s has invalid "
+ "address\n", cfg_if->name);
+ continue;
+ }
+
+ /* Prepare request. */
+ ev->retries = cfzone->notify_retries + 1; /* first + N retries*/
+ ev->msgid = 0;
+ ev->zone = zone;
+ ev->timeout = cfzone->notify_timeout;
+
+ /* Schedule request (30 - 60s random delay). */
+ int tmr_s = 30 + (int)(30.0 * (rand() / (RAND_MAX + 1.0)));
+ pthread_mutex_lock(&zd->lock);
+ ev->timer = evsched_schedule_cb(sch, zones_notify_send, ev,
+ tmr_s * 1000);
+ add_tail(&zd->notify_pending, &ev->n);
+ pthread_mutex_unlock(&zd->lock);
+
+ log_server_info("Scheduled NOTIFY query after %d s to %s:%d\n",
+ tmr_s, cfg_if->address, cfg_if->port);
+ }
+
+ conf_read_unlock();
+
+ return KNOTD_EOK;
+}
+
+int zones_cancel_notify(zonedata_t *zd, notify_ev_t *ev)
+{
+ if (!zd || !ev || !ev->timer) {
+ return KNOTD_EINVAL;
+ }
+
+ /* Wait for event to finish running. */
+#ifdef KNOTD_NOTIFY_DEBUG
+ int pkt_id = ev->msgid; /*< Do not optimize! */
+#endif
+ event_t *tmr = ev->timer;
+ ev->timer = 0;
+ pthread_mutex_unlock(&zd->lock);
+ evsched_cancel(tmr->parent, tmr);
+
+ /* Re-lock and find again (if not deleted). */
+ pthread_mutex_lock(&zd->lock);
+ int match_exists = 0;
+ notify_ev_t *tmpev = 0;
+ WALK_LIST(tmpev, zd->notify_pending) {
+ if (tmpev == ev) {
+ match_exists = 1;
+ break;
+ }
+ }
+
+ /* Event deleted before cancelled. */
+ if (!match_exists) {
+ dbg_notify("notify: NOTIFY event for query ID=%u was "
+ "deleted before cancellation.\n",
+ pkt_id);
+ return KNOTD_EOK;
+
+ }
+
+ /* Free event (won't be scheduled again). */
+ dbg_notify("notify: NOTIFY query ID=%u event cancelled.\n",
+ pkt_id);
+ rem_node(&ev->n);
+ evsched_event_free(tmr->parent, tmr);
+ free(ev);
+ return KNOTD_EOK;
+}
diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h
new file mode 100644
index 0000000..525a78a
--- /dev/null
+++ b/src/knot/server/zones.h
@@ -0,0 +1,264 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file zones.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * Contains functions for updating zone database from configuration.
+ *
+ * \addtogroup server
+ * @{
+ */
+
+#ifndef _KNOTD_ZONES_H_
+#define _KNOTD_ZONES_H_
+
+#include <stddef.h>
+
+#include "common/lists.h"
+#include "common/acl.h"
+#include "common/evsched.h"
+#include "libknot/nameserver/name-server.h"
+#include "libknot/zone/zonedb.h"
+#include "knot/conf/conf.h"
+#include "knot/server/notify.h"
+#include "knot/server/server.h"
+#include "knot/server/journal.h"
+#include "libknot/zone/zone.h"
+#include "libknot/updates/xfr-in.h"
+
+/* Constants. */
+#define SOA_QRY_TIMEOUT 10000 /*!< SOA query timeout (ms). */
+#define IXFR_DBSYNC_TIMEOUT (60*1000) /*!< Database sync timeout = 60s. */
+#define AXFR_BOOTSTRAP_RETRY (60*1000) /*!< Interval between AXFR BS retries. */
+
+/*!
+ * \brief Zone-related data.
+ */
+typedef struct zonedata_t
+{
+ /*! \brief Shortcut to zone config entry. */
+ conf_zone_t *conf;
+
+ /*! \brief Shortcut to server instance. */
+ server_t *server;
+
+ /*! \brief Zone data lock for exclusive access. */
+ pthread_mutex_t lock;
+
+ /*! \brief Access control lists. */
+ acl_t *xfr_out; /*!< ACL for xfr-out.*/
+ acl_t *notify_in; /*!< ACL for notify-in.*/
+ acl_t *notify_out; /*!< ACL for notify-out.*/
+
+ /*! \brief XFR-IN scheduler. */
+ struct {
+ acl_t *acl; /*!< ACL for xfr-in.*/
+ sockaddr_t master; /*!< Master server for xfr-in.*/
+ knot_key_t tsig_key; /*!< Master TSIG key. */
+ struct event_t *timer; /*!< Timer for REFRESH/RETRY. */
+ struct event_t *expire; /*!< Timer for REFRESH. */
+ int next_id; /*!< ID of the next awaited SOA resp.*/
+ pthread_mutex_t lock; /*!< Pending XFR/IN lock. */
+ void *wrkr; /*!< Pending XFR/IN worker. */
+ uint32_t bootstrap_retry;/*!< AXFR/IN bootstrap retry. */
+ } xfr_in;
+
+ /*! \brief List of pending NOTIFY events. */
+ list notify_pending;
+
+ /*! \brief Zone IXFR history. */
+ journal_t *ixfr_db;
+ struct event_t *ixfr_dbsync; /*!< Syncing IXFR db to zonefile. */
+ uint32_t zonefile_serial;
+} zonedata_t;
+
+/*!
+ * \brief Update zone database according to configuration.
+ *
+ * Creates a new database, copies references those zones from the old database
+ * which are still in the configuration, loads any new zones required and
+ * replaces the database inside the namserver.
+ *
+ * It also creates a list of deprecated zones that should be deleted once the
+ * function finishes.
+ *
+ * This function uses RCU mechanism to guard the access to the config and
+ * nameserver and to publish the new database in the nameserver.
+ *
+ * \param[in] conf Configuration.
+ * \param[in] ns Nameserver which holds the zone database.
+ * \param[out] db_old Old database, containing only zones which should be
+ * deleted afterwards.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_EINVAL
+ * \retval KNOTD_ERROR
+ */
+int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns,
+ knot_zonedb_t **db_old);
+
+/*!
+ * \brief Sync zone data back to text zonefile.
+ *
+ * In case when SOA serial of the zonefile differs from the SOA serial of the
+ * loaded zone, zonefile needs to be updated.
+ *
+ * \note Current implementation rewrites the zone file.
+ *
+ * \param zone Evaluated zone.
+ *
+ * \retval KNOTD_EOK if successful.
+ * \retval KNOTD_EINVAL on invalid parameter.
+ * \retval KNOTD_ERROR on unspecified error during processing.
+ */
+int zones_zonefile_sync(knot_zone_t *zone);
+
+int zones_xfr_check_zone(knot_ns_xfr_t *xfr, knot_rcode_t *rcode);
+
+/*!
+ * \brief Processes normal response packet.
+ *
+ * \param nameserver Name server structure to provide the needed data.
+ * \param from Address of the response sender.
+ * \param packet Parsed response packet.
+ * \param response_wire Place for the response in wire format.
+ * \param rsize Input: maximum acceptable size of the response. Output: real
+ * size of the response.
+ *
+ * \retval KNOTD_EOK if a valid response was created.
+ * \retval KNOTD_EINVAL on invalid parameters or packet.
+ * \retval KNOTD_EMALF if an error occured and the response is not valid.
+ */
+int zones_process_response(knot_nameserver_t *nameserver,
+ sockaddr_t *from,
+ knot_packet_t *packet, uint8_t *response_wire,
+ size_t *rsize);
+
+/*!
+ * \brief Decides what type of transfer should be used to update the given zone.
+ *
+ * \param nameserver Name server structure that uses the zone.
+ * \param zone Zone to be updated by the transfer.
+ *
+ * \retval
+ */
+knot_ns_xfr_type_t zones_transfer_to_use(const knot_zone_contents_t *zone);
+
+int zones_save_zone(const knot_ns_xfr_t *xfr);
+
+/*!
+ * \brief Name server config hook.
+ *
+ * Routine for dynamic name server reconfiguration.
+ *
+ * \param conf Current configuration.
+ * \param data Instance of the nameserver structure to update.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL
+ * \retval KNOTD_ERROR
+ */
+int zones_ns_conf_hook(const struct conf_t *conf, void *data);
+
+/*!
+ * \brief Store changesets in journal.
+ *
+ * Changesets will be stored on a permanent storage.
+ * Journal may be compacted, resulting in flattening changeset history.
+ *
+ * \param zone Zone associated with the changeset.
+ * \param src Changesets.
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_EAGAIN if journal needs to be synced with zonefile first.
+ *
+ * \todo Expects the xfr structure to be initialized in some way.
+ */
+int zones_store_changesets(knot_ns_xfr_t *xfr);
+
+/*!
+ * \brief Load changesets from journal.
+ *
+ * Changesets will be stored on a permanent storage.
+ * Journal may be compacted, resulting in flattening changeset history.
+ *
+ * In case of KNOTD_ERANGE error, whole zone content should be sent instead,
+ * as the changeset history cannot be recovered.
+ *
+ * \param zone Zone containing a changeset journal.
+ * \param dst Container to be loaded.
+ * \param from Starting SOA serial (oldest).
+ * \param to Ending SOA serial (newest).
+ *
+ * \retval KNOTD_EOK on success.
+ * \retval KNOTD_EINVAL on invalid parameters.
+ * \retval KNOTD_ERANGE when changeset history cannot be reconstructed.
+ *
+ * \todo Expects the xfr structure to be initialized in some way.
+ */
+int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from,
+ uint32_t serial_to);
+
+/*!
+ * \brief Apply changesets to zone.
+ *
+ * Applies a list of XFR-style changesets to the given zone. Also checks if the
+ * changesets are applicable (i.e. zone is right and has the right serial).
+ *
+ * \param zone Zone to which the changesets should be applied.
+ * \param chsets Changesets to be applied to the zone.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_EINVAL
+ */
+int zones_apply_changesets(knot_ns_xfr_t *xfr);
+
+/*!
+ * \brief Update zone timers.
+ *
+ * REFRESH/RETRY/EXPIRE timers are updated according to SOA.
+ *
+ * \param sched Event scheduler.
+ * \param zone Related zone.
+ * \param cfzone Related zone contents. If NULL, configuration is
+ * reused.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_EINVAL
+ * \retval KNOTD_ERROR
+ */
+int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch);
+
+/*!
+ * \brief Cancel pending NOTIFY timer.
+ *
+ * \warning Expects locked zonedata lock.
+ *
+ * \param zd Zone data.
+ * \param ev NOTIFY event.
+ *
+ * \retval KNOTD_EOK
+ * \retval KNOTD_ERROR
+ * \retval KNOTD_EINVAL
+ */
+int zones_cancel_notify(zonedata_t *zd, notify_ev_t *ev);
+
+#endif // _KNOTD_ZONES_H_
+
+/*! @} */
diff --git a/src/knot/stat/gatherer.c b/src/knot/stat/gatherer.c
new file mode 100644
index 0000000..e8048a1
--- /dev/null
+++ b/src/knot/stat/gatherer.c
@@ -0,0 +1,77 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <pthread.h>
+
+#include "knot/stat/stat-common.h"
+#include "common/slab/malloc.h"
+#include "knot/stat/gatherer.h"
+
+gatherer_t *new_gatherer()
+{
+ gatherer_t *ret;
+
+ if ((ret = malloc(sizeof(gatherer_t))) == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ pthread_mutex_init(&ret->mutex_read, NULL);
+
+ /* TODO check success */
+
+ for (int i = 0; i < FREQ_BUFFER_SIZE; i++) {
+ ret->freq_array[i] = 0;
+ ret->flow_array[i] = NULL;
+ }
+
+ ret->qps = 0.0;
+ ret->udp_qps = 0.0;
+ ret->tcp_qps = 0.0;
+
+ /* CLEANUP */
+ /* currently disabled */
+ /* ret->mean_latency = 0.0;
+ ret->udp_mean_latency = 0.0;
+ ret->tcp_mean_latency = 0.0;
+
+ ret->udp_latency = 0;
+ ret->tcp_latency = 0; */
+
+ ret->udp_queries = 0;
+ ret->tcp_queries = 0;
+
+ return ret;
+}
+
+void gatherer_free(gatherer_t *gath)
+{
+ for (int i = 0; i < FREQ_BUFFER_SIZE; i++) {
+ if (gath->flow_array[i] != NULL) {
+ free(gath->flow_array[i]->addr);
+ free(gath->flow_array[i]);
+ }
+ }
+
+ pthread_mutex_destroy(&(gath->mutex_read));
+
+ pthread_cancel(gath->sleeper_thread);
+
+ pthread_join((gath->sleeper_thread), NULL);
+
+ free(gath);
+}
diff --git a/src/knot/stat/gatherer.h b/src/knot/stat/gatherer.h
new file mode 100644
index 0000000..62b3939
--- /dev/null
+++ b/src/knot/stat/gatherer.h
@@ -0,0 +1,110 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file gatherer.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief Contains gatherer structure and its API.
+ *
+ * \addtogroup statistics
+ * @{
+ */
+
+#ifndef _KNOTD_GATHERER_H_
+#define _KNOTD_GATHERER_H_
+
+#include <stdint.h>
+
+/* The bigger this number, the better the performance of hashing. */
+enum fbs { FREQ_BUFFER_SIZE = 100000 };
+
+/*!
+ * \brief Enum storing protocol codes.
+ */
+enum protocol {
+ stat_UDP,
+ stat_TCP
+};
+
+typedef enum protocol protocol_t;
+
+/*!
+ * \brief Structure used for backward mapping from a simple
+ * hash back to string representation.
+ */
+struct flow_data {
+ char *addr; /*!< IP adress in string format (IP4 only at this time). */
+ uint16_t port; /*!< TCP/UDP port number. */
+ protocol_t protocol;
+};
+
+typedef struct flow_data flow_data_t;
+
+/*!
+ * \brief Gatherer structure, used for gathering statistics from
+ * multiple threads.
+ */
+struct gatherer {
+ pthread_mutex_t mutex_read; /*!< Mutex used when reading values. */
+ double qps; /*!< Queries per second. */
+ double udp_qps; /*!< Queries per second - UDP. */
+ double tcp_qps; /*!< Queries per second - TCP. */
+
+ /*!< \note latency currently disabled */
+ /* double mean_latency;
+ double udp_mean_latency;
+ double tcp_mean_latency;
+ unsigned udp_latency;
+ unsigned tcp_latency; */
+
+ unsigned udp_queries; /*!< Total number of UDP queries for SLEEP_TIME. */
+ unsigned tcp_queries; /*!< Total number of TCP queries for SLEEP_TIME. */
+ /*!
+ * \brief this variable should be much bigger, preferably sparse array
+ * with 2**32 elements (for IPv4). It is an array with query
+ * query frequencies.
+ */
+ unsigned freq_array[FREQ_BUFFER_SIZE];
+ /*!
+ * \brief Used for backward mapping.
+ */
+ flow_data_t *flow_array[FREQ_BUFFER_SIZE];
+ /*!
+ * \brief Thread used for computation of statistics.
+ */
+ pthread_t sleeper_thread;
+};
+
+typedef struct gatherer gatherer_t;
+
+/*!
+ * \brief Creates a new gatherer instance.
+ *
+ * \return Pointer to created structure, NULL otherwise.
+ */
+gatherer_t *new_gatherer();
+
+/*!
+ * \brief Frees a gatherer instance.
+ *
+ * \param gatherer Gatherer instance to be freed.
+ */
+void gatherer_free(gatherer_t *gatherer);
+
+#endif /* _KNOTD_STAT_GATHERER_H_ */
+
+/*! @} */
diff --git a/src/knot/stat/stat-common.h b/src/knot/stat/stat-common.h
new file mode 100644
index 0000000..032e32b
--- /dev/null
+++ b/src/knot/stat/stat-common.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file stat-common.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Common macros for stat.
+ *
+ * \addtogroup statistics
+ * @{
+ */
+
+#ifndef _KNOTD_STAT_COMMON_H_
+#define _KNOTD_STAT_COMMON_H_
+
+#include <stdio.h>
+
+//#define STAT_COMPILE
+#define ST_DEBUG
+
+#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d\n", \
+ __FILE__, __LINE__)
+
+#ifdef ST_DEBUG
+#define dbg_st(msg...) fprintf(stderr, msg)
+#else
+#define dbg_st(msg...)
+#endif
+
+#endif /* _KNOTD_STAT_COMMON_H_ */
+
+/*! @} */
diff --git a/src/knot/stat/stat.c b/src/knot/stat/stat.c
new file mode 100644
index 0000000..a473085
--- /dev/null
+++ b/src/knot/stat/stat.c
@@ -0,0 +1,270 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "knot/stat/stat-common.h"
+#include "knot/stat/stat.h"
+#include "knot/stat/gatherer.h"
+
+#ifdef STAT_COMPILE
+
+/* Static local gatherer variable, to be used with all functions. */
+static gatherer_t *local_gath;
+
+/* CLEANUP */
+/*
+static void stat_inc_latency( stat_t *stat, uint increment )
+{
+ if (stat->protocol==stat_UDP) {
+ local_gath->udp_latency+=increment;
+ } else {
+ local_gath->tcp_latency+=increment;
+ }
+}*/
+/*
+static uint stat_last_query_time( stat_t *stat )
+{
+ return (stat->t2).tv_nsec-(stat->t1).tv_nsec;
+}*/
+
+/*!
+ * \brief Increases query count in the local data gatherer.
+ *
+ * \param stat Current stat instance.
+ */
+static void stat_inc_query(stat_t *stat)
+{
+ if (stat->protocol == stat_UDP) {
+ local_gath->udp_queries++;
+ } else {
+ local_gath->tcp_queries++;
+ }
+}
+
+/*!
+ * \brief Calculates very simple hash from IPv4 address and returns index to
+ * array.
+ *
+ * \param s_addr Socket address structure.
+ * \param protocol Used protocol.
+ *
+ * \return uint Calculated index.
+ */
+static uint return_index(struct sockaddr_in *s_addr , protocol_t protocol)
+{
+ /* TODO IPv6 */
+ /* This is the first "hash" I could think of quickly. */
+ uint ret = 0;
+
+ char str[24];
+ inet_ntop(AF_INET, &s_addr->sin_addr, str, 24);
+
+ for (int i = 0; i < strlen(str); i++) {
+ if (str[i] != '.') {
+ ret += str[i];
+ ret *= (i + 1);
+ }
+ }
+
+ ret += s_addr->sin_port * 7;
+ if (protocol == stat_UDP) {
+ ret *= 3;
+ } else {
+ ret *= 7;
+ }
+ ret %= FREQ_BUFFER_SIZE;
+ /* Effectively uses only end of the hash, maybe hash the
+ * resulting number once again to get 0 <= n < 10000. */
+ return ret;
+}
+
+/*!
+ * \brief Adds data to local gatherer structure.
+ *
+ * \param stat Current stat variable.
+ *
+ * \retval 0 on success.
+ * \retval -1 on memory error.
+ */
+static int stat_gatherer_add_data(stat_t *stat)
+{
+ /* TODO IPv6*/
+ uint index = return_index(stat->s_addr, stat->protocol);
+ if (!local_gath->freq_array[index]) {
+ char addr[24];
+ inet_ntop(AF_INET, &stat->s_addr->sin_addr, addr, 24);
+ flow_data_t *tmp;
+ tmp = malloc(sizeof(flow_data_t));
+ if (tmp == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+ tmp->addr = malloc(sizeof(char) * 24);
+ if (tmp->addr == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+ strcpy(tmp->addr, addr);
+ tmp->port = stat->s_addr->sin_port;
+ tmp->protocol = stat->protocol;
+ local_gath->flow_array[index] = tmp;
+ }
+
+ //TODO add a check here, whether hashing fction performs well enough
+
+ local_gath->freq_array[index] += 1;
+
+ return 0;
+}
+
+/*!
+ * \brief Resets logging array.
+ */
+static void stat_reset_gatherer_array()
+{
+ for (int i = 0; i < FREQ_BUFFER_SIZE; i++) {
+ local_gath->freq_array[i] = 0;
+ }
+}
+
+/*!
+ * \brief Sleeps for given time and then runs all the computations,
+ * results of which are stored in local gatherer.
+ */
+static void stat_sleep_compute()
+{
+ while (1) {
+ sleep(SLEEP_TIME);
+
+ for (int i = 0; i < FREQ_BUFFER_SIZE; i++) {
+ if (local_gath->freq_array[i] >
+ ACTIVE_FLOW_THRESHOLD) {
+ dbg_st("too much activity at index %d:"
+ " %d queries adress: %s port %d"
+ " protocol %d\n",
+ i, local_gath->freq_array[i],
+ local_gath->flow_array[i]->addr,
+ local_gath->flow_array[i]->port,
+ local_gath->flow_array[i]->protocol);
+ }
+ }
+
+ pthread_mutex_lock(&(local_gath->mutex_read));
+
+ local_gath->udp_qps = local_gath->udp_queries /
+ (double)SLEEP_TIME;
+ local_gath->tcp_qps = local_gath->tcp_queries /
+ (double)SLEEP_TIME;
+ local_gath->qps = local_gath->udp_qps + local_gath->tcp_qps;
+
+ /* following code needs usage of
+ * gettimeofday, which is currently disabled */
+ /* CLEANUP */
+/* local_gath->udp_mean_latency=((double)local_gath->udp_latency/
+ (double)local_gath->udp_queries);
+ local_gath->tcp_mean_latency=((double)local_gath->tcp_latency/
+ (double)local_gath->tcp_queries);
+ local_gath->mean_latency = (local_gath->udp_mean_latency +
+ local_gath->tcp_mean_latency)/2; */
+
+ local_gath->udp_queries = 0;
+ local_gath->tcp_queries = 0;
+
+ /* same thing as above applies here */
+
+/* local_gath->tcp_latency = 0;
+ local_gath->udp_latency = 0; */
+
+ pthread_mutex_unlock(&(local_gath->mutex_read));
+
+ stat_reset_gatherer_array(local_gath);
+
+ dbg_st("qps_udp: %f\n", local_gath->udp_qps);
+/* dbg_st("mean_lat_udp: %f\n", local_gath->udp_mean_latency); */
+
+ dbg_st("qps_tcp: %f\n", local_gath->tcp_qps);
+/* dbg_st("mean_lat_tcp: %f\n", local_gath->tcp_mean_latency); */
+
+ dbg_st("UDP/TCP ratio %f\n",
+ local_gath->udp_qps / local_gath->tcp_qps);
+ }
+}
+
+stat_t *stat_new()
+{
+ stat_t *ret;
+
+ if ((ret = malloc(sizeof(stat_t))) == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ return ret;
+}
+
+void stat_set_protocol(stat_t *stat, int protocol)
+{
+ stat->protocol = protocol;
+}
+
+void stat_get_first(stat_t *stat , struct sockaddr_in *s_addr)
+{
+ /* CLEANUP */
+// gettimeofday(&stat->t2, NULL);
+ stat->s_addr = s_addr;
+// check if s_addr does not get overwritten
+}
+
+void stat_get_second(stat_t *stat)
+{
+ /* CLEANUP */
+// gettimeofday(&stat->t2, NULL);
+ stat_inc_query(stat);
+// stat_inc_latency(stat, stat_last_query_time(stat));
+ stat_gatherer_add_data(stat);
+}
+
+void stat_free(stat_t *stat)
+{
+ free(stat);
+}
+
+void stat_static_gath_init()
+{
+ local_gath = new_gatherer();
+}
+
+void stat_static_gath_start()
+{
+ pthread_create(&(local_gath->sleeper_thread), NULL,
+ (void *) &stat_sleep_compute, NULL);
+}
+
+void stat_static_gath_free()
+{
+ gatherer_free(local_gath);
+}
+
+#endif /* STAT_COMPILE */
diff --git a/src/knot/stat/stat.h b/src/knot/stat/stat.h
new file mode 100644
index 0000000..a82f130
--- /dev/null
+++ b/src/knot/stat/stat.h
@@ -0,0 +1,157 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file stat.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief Contains statistics structure and its API.
+ *
+ * \addtogroup statistics
+ * @{
+ */
+
+#ifndef _KNOTD_STAT_H_
+#define _KNOTD_STAT_H_
+
+#include <time.h>
+#include <stdbool.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "knot/stat/gatherer.h"
+
+#ifdef STAT_COMPILE
+#define STAT_INIT(x) x = stat_new()
+#else
+#define STAT_INIT(x) x = NULL //UNUSED(x)
+#endif /* STAT_COMPILE */
+
+/* Determines how long until the sleeper thread
+ * wakes up and runs computations.
+ */
+static uint const SLEEP_TIME = 15;
+
+/* Sets threshold for active flow detection, will
+ * probably have to be changed. */
+static uint const ACTIVE_FLOW_THRESHOLD = 10;
+
+/*!
+ * \brief Statistics structure, unique for each UDP/TCP thread.
+ */
+struct stat_stat {
+// struct timespec t1, t2; /* Currently disabled */
+ protocol_t protocol; /*!< Flags. */
+ struct sockaddr_in *s_addr;
+// gatherer_t *gatherer; / * not needed when using static gatherer. */
+};
+
+typedef struct stat_stat stat_t;
+
+/*!
+ * \brief Creates new stat_t structure.
+ *
+ * \return Newly allocated and initialized stat structure, NULL on errror.
+ */
+#ifdef STAT_COMPILE
+stat_t *stat_new();
+#else
+inline stat_t *stat_new()
+{
+ return NULL;
+}
+#endif /* STAT_COMPILE */
+
+/*!
+ * \brief Sets a protocol for stat_t structure. Options are stat_UDP, stat_TCP.
+ *
+ * \param stat Stat_t instance (usually newly created).
+ * \param protocol Protocol to be assigned to stat structure.
+ */
+#ifdef STAT_COMPILE
+void stat_set_protocol(stat_t *stat, int protocol);
+#else
+static inline void stat_set_protocol(stat_t *stat, int protocol) {}
+#endif /* STAT_COMPILE */
+
+/*!
+ * \brief Gets the time from a processing function.
+ *
+ * \param stat Current instance of stat_t.
+ * \param s_addr Sockaddr structure to be used later for statistics.
+ */
+#ifdef STAT_COMPILE
+#warning "stat fixme: pass sockaddr* for generic _in and _in6 support"
+void stat_get_first(stat_t *stat, struct sockaddr_in *s_addr);
+#else
+static inline void stat_get_first(stat_t *stat, struct sockaddr *s_addr) {}
+#endif /* STAT_COMPILE */
+
+/*!
+ * \brief Gets time from a processing fuction and changes
+ * the corresponding variables.
+ *
+ * \param stat Current stat_t instance.
+ */
+#ifdef STAT_COMPILE
+void stat_get_second(stat_t *stat);
+#else
+static inline void stat_get_second(stat_t *stat) {}
+#endif /* STAT_COMPILE */
+
+/*!
+ * \brief Frees stat_t structure.
+ *
+ * \param stat Pointer to stat structure to be deallocated.
+ */
+#ifdef STAT_COMPILE
+void stat_free(stat_t *stat);
+#else
+static inline void stat_free(stat_t *stat) {}
+#endif /* STAT_COMPILE */
+
+/*!
+ * \brief Initializes static gatherer.
+ */
+#ifdef STAT_COMPILE
+void stat_static_gath_init();
+#else
+static inline void stat_static_gath_init() {}
+#endif /* STAT_COMPILE */
+
+/*!
+ * \brief Starts static gatherer's sleeper thread.
+ */
+#ifdef STAT_COMPILE
+void stat_static_gath_start();
+#else
+static inline void stat_static_gath_start() {}
+#endif /* STAT_COMPILE */
+
+/*!
+ * \brief Frees static gatherer, calls gatherer_free().
+ */
+#ifdef STAT_COMPILE
+void stat_static_gath_free();
+#else
+static inline void stat_static_gath_free() {}
+#endif /* STAT_COMPILE */
+
+#endif /* _KNOTD_STAT_H_ */
+
+/*! @} */
diff --git a/src/knot/zone/zone-dump-text.c b/src/knot/zone/zone-dump-text.c
new file mode 100644
index 0000000..f7899a1
--- /dev/null
+++ b/src/knot/zone/zone-dump-text.c
@@ -0,0 +1,1083 @@
+/*!
+ * \file zone-dump-text.c
+ *
+ * \author modifications (non-buffer implementation, zone-specific functions)
+ * by Jan Kadlec <jan.kadlec@nic.cz>,
+ * conversion functions by NLnet Labs,
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ * b64ntop by ISC.
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <assert.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "libknot/libknot.h"
+#include "libknot/common.h"
+#include "common/skip-list.h"
+#include "common/base32hex.h"
+
+/* TODO max length of alg */
+
+enum uint_max_length {
+ U8_MAX_STR_LEN = 4, U16_MAX_STR_LEN = 6,
+ U32_MAX_STR_LEN = 11, MAX_RR_TYPE_LEN = 20,
+ MAX_NSEC_BIT_STR_LEN = 4096,
+ };
+
+#define APL_NEGATION_MASK 0x80U
+#define APL_LENGTH_MASK (~APL_NEGATION_MASK)
+
+/* RFC 4025 - codes for different types that IPSECKEY can hold. */
+#define IPSECKEY_NOGATEWAY 0
+#define IPSECKEY_IP4 1
+#define IPSECKEY_IP6 2
+#define IPSECKEY_DNAME 3
+
+/* Following copyrights are only valid for b64_ntop function */
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int b64_ntop(uint8_t const *src, size_t srclength, char *target,
+ size_t targsize) {
+ size_t datalength = 0;
+ uint8_t input[3];
+ uint8_t output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* Taken from RFC 4398, section 2.1. */
+knot_lookup_table_t knot_dns_certificate_types[] = {
+/* 0 Reserved */
+ { 1, "PKIX" }, /* X.509 as per PKIX */
+ { 2, "SPKI" }, /* SPKI cert */
+ { 3, "PGP" }, /* OpenPGP packet */
+ { 4, "IPKIX" }, /* The URL of an X.509 data object */
+ { 5, "ISPKI" }, /* The URL of an SPKI certificate */
+ { 6, "IPGP" }, /* The fingerprint and URL of an OpenPGP packet */
+ { 7, "ACPKIX" }, /* Attribute Certificate */
+ { 8, "IACPKIX" }, /* The URL of an Attribute Certificate */
+ { 253, "URI" }, /* URI private */
+ { 254, "OID" }, /* OID private */
+/* 255 Reserved */
+/* 256-65279 Available for IANA assignment */
+/* 65280-65534 Experimental */
+/* 65535 Reserved */
+ { 0, NULL }
+};
+
+/* Taken from RFC 2535, section 7. */
+knot_lookup_table_t knot_dns_algorithms[] = {
+ { 1, "RSAMD5" }, /* RFC 2537 */
+ { 2, "DH" }, /* RFC 2539 */
+ { 3, "DSA" }, /* RFC 2536 */
+ { 4, "ECC" },
+ { 5, "RSASHA1" }, /* RFC 3110 */
+ { 252, "INDIRECT" },
+ { 253, "PRIVATEDNS" },
+ { 254, "PRIVATEOID" },
+ { 0, NULL }
+};
+
+static int get_bit(uint8_t bits[], size_t index)
+{
+ /*
+ * The bits are counted from left to right, so bit #0 is the
+ * left most bit.
+ */
+ return bits[index / 8] & (1 << (7 - index % 8));
+}
+
+static inline uint8_t * rdata_item_data(knot_rdata_item_t item)
+{
+ return (uint8_t *)(item.raw_data + 1);
+}
+
+static inline uint16_t rdata_item_size(knot_rdata_item_t item)
+{
+ return item.raw_data[0];
+}
+
+char *rdata_dname_to_string(knot_rdata_item_t item)
+{
+ return knot_dname_to_str(item.dname);
+}
+
+char *rdata_dns_name_to_string(knot_rdata_item_t item)
+{
+ return knot_dname_to_str(item.dname);
+}
+
+static char *rdata_txt_data_to_string(const uint8_t *data)
+{
+ uint8_t length = data[0];
+ size_t i;
+
+ if (length == 0) {
+ return NULL;
+ }
+
+ /*
+ * 3 because: opening '"', closing '"', and \0 at the end.
+ * Times 2 because string can be all "double chars".
+ */
+ size_t current_length = sizeof(char) * (length * 2 + 3);
+ char *ret = malloc(current_length);
+ if (ret == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ memset(ret, 0, sizeof(char) * (length * 2 + 3));
+
+
+ strcat(ret, "\"");
+
+ for (i = 1; i <= length; i++) {
+ char ch = (char) data[i];
+ if (isprint((int)ch)) {
+ if (ch == '"' || ch == '\\') {
+ strcat(ret, "\"");
+ }
+ /* for the love of god, how to this better,
+ but w/o obscure self-made functions */
+ char tmp_str[2];
+ tmp_str[0] = ch;
+ tmp_str[1] = 0;
+ strcat(ret, tmp_str);
+ } else {
+ strcat(ret, "\\");
+ char tmp_str[2];
+ tmp_str[0] = ch - '0';
+ tmp_str[1] = 0;
+
+ strcat(ret, tmp_str);
+ }
+ }
+ strcat(ret, "\"");
+
+ return ret;
+}
+
+char *rdata_text_to_string(knot_rdata_item_t item)
+{
+ uint16_t size = item.raw_data[0];
+ char *ret = malloc(sizeof(char) * size * 2) ;
+ if (ret == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ memset(ret, 0, sizeof(char) * size);
+ const uint8_t *data = (uint8_t *)(item.raw_data + 1);
+ size_t read_count = 0;
+ while (read_count < size) {
+ assert(read_count <= size);
+ char *txt = rdata_txt_data_to_string(data + read_count);
+ if (txt == NULL) {
+ free(ret);
+ return NULL;
+ }
+ read_count += strlen(txt) - 1;
+ /* Create delimiter. */
+ char del[2];
+ del[0] = ' ';
+ del[1] = '\0';
+ strcat(ret, txt);
+ strcat(ret, del);
+ free(txt);
+ }
+
+ return ret;
+}
+
+char *rdata_byte_to_string(knot_rdata_item_t item)
+{
+ assert(item.raw_data[0] == 1);
+ uint8_t data = item.raw_data[1];
+ char *ret = malloc(sizeof(char) * U8_MAX_STR_LEN);
+ snprintf(ret, U8_MAX_STR_LEN, "%d", (char) data);
+ return ret;
+}
+
+char *rdata_short_to_string(knot_rdata_item_t item)
+{
+ uint16_t data = knot_wire_read_u16(rdata_item_data(item));
+ char *ret = malloc(sizeof(char) * U16_MAX_STR_LEN);
+ snprintf(ret, U16_MAX_STR_LEN, "%u", data);
+ /* XXX Use proper macros - see response tests*/
+ /* XXX check return value, return NULL on failure */
+ return ret;
+}
+
+char *rdata_long_to_string(knot_rdata_item_t item)
+{
+ uint32_t data = knot_wire_read_u32(rdata_item_data(item));
+ char *ret = malloc(sizeof(char) * U32_MAX_STR_LEN);
+ /* u should be enough */
+ snprintf(ret, U32_MAX_STR_LEN, "%u", data);
+ return ret;
+}
+
+char *rdata_a_to_string(knot_rdata_item_t item)
+{
+ /* 200 seems like a little too much */
+ char *ret = malloc(sizeof(char) * 200);
+ if (inet_ntop(AF_INET, rdata_item_data(item), ret, 200)) {
+ return ret;
+ } else {
+ return NULL;
+ }
+}
+
+char *rdata_aaaa_to_string(knot_rdata_item_t item)
+{
+ char *ret = malloc(sizeof(char) * 200);
+ if (inet_ntop(AF_INET6, rdata_item_data(item), ret, 200)) {
+ return ret;
+ } else {
+ return NULL;
+ }
+}
+
+char *rdata_rrtype_to_string(knot_rdata_item_t item)
+{
+ uint16_t type = knot_wire_read_u16(rdata_item_data(item));
+ const char *tmp = knot_rrtype_to_string(type);
+ char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN);
+ strncpy(ret, tmp, MAX_RR_TYPE_LEN);
+ return ret;
+}
+
+char *rdata_algorithm_to_string(knot_rdata_item_t item)
+{
+ uint8_t id = *rdata_item_data(item);
+ char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN);
+ knot_lookup_table_t *alg
+ = knot_lookup_by_id(knot_dns_algorithms, id);
+ if (alg) {
+ strncpy(ret, alg->name, MAX_RR_TYPE_LEN);
+ } else {
+ snprintf(ret, U8_MAX_STR_LEN, "%u", id);
+ }
+
+ return ret;
+}
+
+char *rdata_certificate_type_to_string(knot_rdata_item_t item)
+{
+ uint16_t id = knot_wire_read_u16(rdata_item_data(item));
+ char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN);
+ knot_lookup_table_t *type
+ = knot_lookup_by_id(knot_dns_certificate_types, id);
+ if (type) {
+ strncpy(ret, type->name, MAX_RR_TYPE_LEN);
+ } else {
+ snprintf(ret, U16_MAX_STR_LEN, "%u", id);
+ }
+
+ return ret;
+}
+
+char *rdata_period_to_string(knot_rdata_item_t item)
+{
+ /* uint32 but read 16 XXX */
+ uint32_t period = knot_wire_read_u32(rdata_item_data(item));
+ char *ret = malloc(sizeof(char) * U32_MAX_STR_LEN);
+ snprintf(ret, U32_MAX_STR_LEN, "%u", period);
+ return ret;
+}
+
+char *rdata_time_to_string(knot_rdata_item_t item)
+{
+ time_t time = (time_t) knot_wire_read_u32(rdata_item_data(item));
+ struct tm tm_conv;
+ if (gmtime_r(&time, &tm_conv) == 0) {
+ return 0;
+ }
+ char *ret = malloc(sizeof(char) * 15);
+ if (strftime(ret, 15, "%Y%m%d%H%M%S", &tm_conv)) {
+ return ret;
+ } else {
+ free(ret);
+ return 0;
+ }
+}
+
+char *rdata_base32_to_string(knot_rdata_item_t item)
+{
+ int length;
+ size_t size = rdata_item_size(item);
+ if (size == 0) {
+ char *ret = malloc(sizeof(char) * 2);
+ ret[0] = '-';
+ ret[1] = '\0';
+ return ret;
+ }
+
+ size -= 1; // remove length byte from count
+ char *ret = NULL;
+ length = base32hex_encode_alloc((char *)rdata_item_data(item) + 1,
+ size, &ret);
+ if (length > 0) {
+ return ret;
+ } else {
+ free(ret);
+ return NULL;
+ }
+}
+
+char *rdata_base64_to_string(knot_rdata_item_t item)
+{
+ int length;
+ size_t size = rdata_item_size(item);
+ char *ret = malloc((sizeof(char) * 2 * size) + 1 * sizeof(char));
+ length = b64_ntop(rdata_item_data(item), size,
+ ret, (sizeof(char)) * (size * 2 + 1));
+ if (length > 0) {
+ return ret;
+ } else {
+ free(ret);
+ return NULL;
+ }
+}
+
+char *hex_to_string(const uint8_t *data, size_t size)
+{
+ static const char hexdigits[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+ size_t i;
+
+ char *ret = malloc(sizeof(char) * (size * 2 + 1));
+
+ for (i = 0; i < size * 2; i += 2) {
+ uint8_t octet = *data++;
+ ret[i] = hexdigits [octet >> 4];
+ ret[i + 1] = hexdigits [octet & 0x0f];
+ }
+
+ ret[i] = '\0';
+
+ return ret;
+}
+
+char *rdata_hex_to_string(knot_rdata_item_t item)
+{
+ return hex_to_string(rdata_item_data(item), rdata_item_size(item));
+}
+
+char *rdata_hexlen_to_string(knot_rdata_item_t item)
+{
+ if(rdata_item_size(item) <= 1) {
+ // NSEC3 salt hex can be empty
+ char *ret = malloc(sizeof(char) * 2);
+ ret[0] = '-';
+ ret[1] = '\0';
+ return ret;
+ } else {
+ return hex_to_string(rdata_item_data(item) + 1,
+ rdata_item_size(item) - 1);
+ }
+}
+
+char *rdata_nsap_to_string(knot_rdata_item_t item)
+{
+ char *ret = malloc(sizeof(char) * (rdata_item_size(item) + 3));
+ memcpy(ret, "0x", strlen("0x"));
+ char *converted = hex_to_string(rdata_item_data(item),
+ rdata_item_size(item));
+ strcat(ret, converted);
+ free(converted);
+ return ret;
+}
+
+char *rdata_apl_to_string(knot_rdata_item_t item)
+{
+ uint8_t *data = rdata_item_data(item);
+ uint16_t address_family = knot_wire_read_u16(data);
+ uint8_t prefix = data[2];
+ uint8_t length = data[3];
+ int negated = length & APL_NEGATION_MASK;
+ int af = -1;
+
+ char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
+
+ memset(ret, 0, MAX_NSEC_BIT_STR_LEN);
+
+ length &= APL_LENGTH_MASK;
+ switch (address_family) {
+ case 1: af = AF_INET; break;
+ case 2: af = AF_INET6; break;
+ }
+
+ if (af != -1) {
+ char text_address[1000];
+ uint8_t address[128];
+ memset(address, 0, sizeof(address));
+ memcpy(address, data + 4, length);
+ if (inet_ntop(af, address,
+ text_address,
+ sizeof(text_address))) {
+ snprintf(ret, sizeof(text_address) +
+ U32_MAX_STR_LEN * 2,
+ "%s%d:%s/%d",
+ negated ? "!" : "",
+ (int) address_family,
+ text_address,
+ (int) prefix);
+ }
+ }
+
+ return ret;
+
+ /*
+ int result = 0;
+ buffer_type packet;
+
+ buffer_create_from(
+ &packet, rdata_item_data(rdata), rdata_atom_size(rdata));
+
+ if (buffer_available(&packet, 4)) {
+ uint16_t address_family = buffer_read_u16(&packet);
+ uint8_t prefix = buffer_read_u8(&packet);
+ uint8_t length = buffer_read_u8(&packet);
+ int negated = length & APL_NEGATION_MASK;
+ int af = -1;
+
+ length &= APL_LENGTH_MASK;
+ switch (address_family) {
+ case 1: af = AF_INET; break;
+ *case 2: af = AF_INET6; break;
+ }
+ if (af != -1 && buffer_available(&packet, length)) {
+ char text_address[1000];
+ uint8_t address[128];
+ memset(address, 0, sizeof(address));
+ buffer_read(&packet, address, length);
+ if (inet_ntop(af, address, text_address,
+ sizeof(text_address))) {
+ buffer_printf(output, "%s%d:%s/%d",
+ negated ? "!" : "",
+ (int) address_family,
+ text_address,
+ (int) prefix);
+ result = 1;
+ }
+ }
+ }
+ return result;
+ */
+
+
+}
+
+char *rdata_services_to_string(knot_rdata_item_t item)
+{
+ uint8_t *data = rdata_item_data(item);
+ uint8_t protocol_number = data[0];
+ ssize_t bitmap_size = rdata_item_size(item) - 1;
+ uint8_t *bitmap = data + 1;
+ struct protoent *proto = getprotobynumber(protocol_number);
+
+ char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
+
+ memset(ret, 0, MAX_NSEC_BIT_STR_LEN);
+
+ if (proto) {
+ int i;
+
+ strcpy(ret, proto->p_name);
+
+ strcat(ret, " ");
+
+ for (i = 0; i < bitmap_size * 8; ++i) {
+ if (get_bit(bitmap, i)) {
+ struct servent *service =
+ getservbyport((int)htons(i),
+ proto->p_name);
+ if (service) {
+ strcat(ret, service->s_name);
+ strcat(ret, " ");
+ } else {
+ char tmp[U32_MAX_STR_LEN];
+ snprintf(tmp, U32_MAX_STR_LEN,
+ "%d ", i);
+ strcat(ret, tmp);
+ }
+ }
+ }
+ }
+
+ return ret;
+
+ /*
+ int result = 0;
+ uint8_t protocol_number = buffer_read_u8(&packet);
+ ssize_t bitmap_size = buffer_remaining(&packet);
+ uint8_t *bitmap = buffer_current(&packet);
+ struct protoent *proto = getprotobynumber(protocol_number);
+
+
+ if (proto) {
+ int i;
+
+ strcpy(ret, proto->p_name);
+
+ for (i = 0; i < bitmap_size * 8; ++i) {
+ if (get_bit(bitmap, i)) {
+ struct servent *service =
+ getservbyport((int)htons(i),
+ proto->p_name);
+ if (service) {
+ buffer_printf(output, " %s",
+ service->s_name);
+ } else {
+ buffer_printf(output, " %d", i);
+ }
+ }
+ }
+ result = 1;
+ }
+ return ret;
+ */
+}
+
+char *rdata_ipsecgateway_to_string(knot_rdata_item_t item,
+ const knot_rrset_t *rrset)
+{
+ const knot_rdata_item_t *gateway_type_item =
+ knot_rdata_item(knot_rrset_rdata(rrset), 1);
+ if (gateway_type_item == NULL) {
+ return NULL;
+ }
+ /* First two bytes store length. */
+ int gateway_type = ((uint8_t *)(gateway_type_item->raw_data))[2];
+ switch(gateway_type) {
+ case IPSECKEY_NOGATEWAY: {
+ char *ret = malloc(sizeof(char) * 4);
+ if (ret == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ memset(ret, 0, sizeof(char) * 4);
+ memcpy(ret, ".", 4);
+/* ret[0] = '\"';
+ ret[1] = '.';
+ ret[2] = '\"';
+ ret[3] = '\0'; */
+ return ret;
+ }
+ case IPSECKEY_IP4:
+ return rdata_a_to_string(item);
+ case IPSECKEY_IP6:
+ return rdata_aaaa_to_string(item);
+ case IPSECKEY_DNAME:
+ return rdata_dname_to_string(item);
+ default:
+ return NULL;
+ }
+
+ /* Flow *should* not get here. */
+ return NULL;
+}
+
+char *rdata_nxt_to_string(knot_rdata_item_t item)
+{
+ size_t i;
+ uint8_t *bitmap = rdata_item_data(item);
+ size_t bitmap_size = rdata_item_size(item);
+
+ char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
+
+ memset(ret, 0, MAX_NSEC_BIT_STR_LEN);
+
+ for (i = 0; i < bitmap_size * 8; ++i) {
+ if (get_bit(bitmap, i)) {
+ strcat(ret, knot_rrtype_to_string(i));
+ strcat(ret, " ");
+ }
+ }
+
+ return ret;
+}
+
+
+char *rdata_nsec_to_string(knot_rdata_item_t item)
+{
+ /* CLEANUP */
+// int insert_space = 0;
+
+ char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
+
+ memset(ret, 0, MAX_NSEC_BIT_STR_LEN);
+
+ uint8_t *data = rdata_item_data(item);
+
+ int increment = 0;
+
+ for (int i = 0; i < rdata_item_size(item); i += increment) {
+ increment = 0;
+ uint8_t window = data[i];
+ increment++;
+
+ uint8_t bitmap_size = data[i + increment];
+ increment++;
+
+ uint8_t *bitmap = malloc(sizeof(uint8_t) * bitmap_size);
+
+ memcpy(bitmap, data + i + increment,
+ bitmap_size);
+
+ increment += bitmap_size;
+
+ for (int j = 0; j < bitmap_size * 8; j++) {
+ if (get_bit(bitmap, j)) {
+ strcat(ret,
+ knot_rrtype_to_string(j +
+ window * 256));
+ strcat(ret, " ");
+ }
+ }
+
+ free(bitmap);
+ }
+
+ return ret;
+
+ /* CLEANUP */
+/* while (buffer_available(&packet, 2)) {
+ uint8_t window = buffer_read_u8(&packet);
+ uint8_t bitmap_size = buffer_read_u8(&packet);
+ uint8_t *bitmap = buffer_current(&packet);
+ int i;
+
+ if (!buffer_available(&packet, bitmap_size)) {
+ buffer_set_position(output, saved_position);
+ return 0;
+ }
+
+ for (i = 0; i < bitmap_size * 8; ++i) {
+ if (get_bit(bitmap, i)) {
+ buffer_printf(output,
+ "%s%s",
+ insert_space ? " " : "",
+ rrtype_to_string(
+ window * 256 + i));
+ insert_space = 1;
+ }
+ }
+ buffer_skip(&packet, bitmap_size);
+ }
+
+ return 1; */
+}
+
+char *rdata_unknown_to_string(knot_rdata_item_t item)
+{
+ uint16_t size = rdata_item_size(item);
+ char *ret =
+ malloc(sizeof(char) * (rdata_item_size(item) +
+ strlen("\\# ") + U16_MAX_STR_LEN));
+ snprintf(ret, strlen("\\# ") + U16_MAX_STR_LEN, "%lu",
+ (unsigned long) size);
+ char *converted = hex_to_string(rdata_item_data(item), size);
+ strcat(ret, converted);
+ free(converted);
+ return ret;
+}
+
+char *rdata_loc_to_string(knot_rdata_item_t item)
+{
+ return rdata_unknown_to_string(item);
+}
+
+typedef char * (*item_to_string_t)(knot_rdata_item_t);
+
+static item_to_string_t item_to_string_table[KNOT_RDATA_ZF_UNKNOWN + 1] = {
+ rdata_dname_to_string,
+ rdata_dns_name_to_string,
+ rdata_text_to_string,
+ rdata_byte_to_string,
+ rdata_short_to_string,
+ rdata_long_to_string,
+ rdata_a_to_string,
+ rdata_aaaa_to_string,
+ rdata_rrtype_to_string,
+ rdata_algorithm_to_string,
+ rdata_certificate_type_to_string,
+ rdata_period_to_string,
+ rdata_time_to_string,
+ rdata_base64_to_string,
+ rdata_base32_to_string,
+ rdata_hex_to_string,
+ rdata_hexlen_to_string,
+ rdata_nsap_to_string,
+ rdata_apl_to_string,
+ NULL, //rdata_ipsecgateway_to_string,
+ rdata_services_to_string,
+ rdata_nxt_to_string,
+ rdata_nsec_to_string,
+ rdata_loc_to_string,
+ rdata_unknown_to_string
+};
+
+char *rdata_item_to_string(knot_rdata_zoneformat_t type,
+ knot_rdata_item_t item)
+{
+ return item_to_string_table[type](item);
+}
+
+/* CLEANUP */
+/*void knot_zone_tree_apply_inorder(knot_zone_t *zone,
+ void (*function)(knot_node_t *node, void *data),
+ void *data); */
+
+void rdata_dump_text(const knot_rdata_t *rdata, uint16_t type, FILE *f,
+ const knot_rrset_t *rrset)
+{
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ char *item_str = NULL;
+ for (int i = 0; i < rdata->count; i++) {
+ /* Workaround for IPSec gateway. */
+ if (desc->zoneformat[i] == KNOT_RDATA_ZF_IPSECGATEWAY) {
+ item_str = rdata_ipsecgateway_to_string(rdata->items[i],
+ rrset);
+ } else {
+ item_str = rdata_item_to_string(desc->zoneformat[i],
+ rdata->items[i]);
+ }
+ if (item_str == NULL) {
+ item_str =
+ rdata_item_to_string(KNOT_RDATA_ZF_UNKNOWN,
+ rdata->items[i]);
+ }
+ if (i != rdata->count - 1) {
+ fprintf(f, "%s ", item_str);
+ } else {
+ fprintf(f, "%s", item_str);
+ }
+ free(item_str);
+ }
+ fprintf(f, "\n");
+}
+
+void dump_rrset_header(const knot_rrset_t *rrset, FILE *f)
+{
+ char *name = knot_dname_to_str(rrset->owner);
+ fprintf(f, "%-20s ", name);
+ free(name);
+ fprintf(f, "%-5u ", rrset->ttl);
+ fprintf(f, "%-2s ", knot_rrclass_to_string(rrset->rclass));
+ fprintf(f, "%-5s ", knot_rrtype_to_string(rrset->type));
+}
+
+void rrsig_set_dump_text(knot_rrset_t *rrsig, FILE *f)
+{
+ dump_rrset_header(rrsig, f);
+ knot_rdata_t *tmp = rrsig->rdata;
+
+ while (tmp->next != rrsig->rdata) {
+ rdata_dump_text(tmp, KNOT_RRTYPE_RRSIG, f, rrsig);
+ dump_rrset_header(rrsig, f);
+ tmp = tmp->next;
+ }
+
+ rdata_dump_text(tmp, KNOT_RRTYPE_RRSIG, f, rrsig);
+}
+
+
+void rrset_dump_text(const knot_rrset_t *rrset, FILE *f)
+{
+ dump_rrset_header(rrset, f);
+ knot_rdata_t *tmp = rrset->rdata;
+
+ while (tmp->next != rrset->rdata) {
+ rdata_dump_text(tmp, rrset->type, f, rrset);
+ dump_rrset_header(rrset, f);
+ tmp = tmp->next;
+ }
+
+ rdata_dump_text(tmp, rrset->type, f, rrset);
+ knot_rrset_t *rrsig_set = rrset->rrsigs;
+ if (rrsig_set != NULL) {
+ rrsig_set_dump_text(rrsig_set, f);
+ }
+}
+
+struct dump_param {
+ FILE *f;
+ const knot_dname_t *origin;
+};
+
+void apex_node_dump_text(knot_node_t *node, FILE *f)
+{
+ knot_rrset_t dummy_rrset;
+ dummy_rrset.type = KNOT_RRTYPE_SOA;
+ knot_rrset_t *tmp_rrset =
+ (knot_rrset_t *)gen_tree_find(node->rrset_tree,
+ &dummy_rrset);
+ assert(tmp_rrset);
+ rrset_dump_text(tmp_rrset, f);
+
+ const knot_rrset_t **rrsets =
+ knot_node_rrsets(node);
+
+ for (int i = 0; i < node->rrset_count; i++) {
+ if (rrsets[i]->type != KNOT_RRTYPE_SOA) {
+ rrset_dump_text(rrsets[i], f);
+ }
+ }
+
+ free(rrsets);
+}
+
+void node_dump_text(knot_node_t *node, void *data)
+{
+ struct dump_param *param;
+ param = (struct dump_param *)data;
+ FILE *f = param->f;
+ const knot_dname_t *origin = param->origin;
+
+ /* pointers should do in this case */
+ if (node->owner == origin) {
+ apex_node_dump_text(node, f);
+ return;
+ }
+
+ const knot_rrset_t **rrsets =
+ knot_node_rrsets(node);
+
+ for (int i = 0; i < node->rrset_count; i++) {
+ rrset_dump_text(rrsets[i], f);
+ }
+
+ free(rrsets);
+}
+
+int zone_dump_text(knot_zone_contents_t *zone, const char *filename)
+{
+ FILE *f = fopen(filename, "w");
+ if (f == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ fprintf(f, ";Dumped using %s v. %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+
+ struct dump_param param;
+ param.f = f;
+ assert(zone->apex != NULL && zone->apex->owner != NULL);
+ param.origin = knot_node_owner(knot_zone_contents_apex(zone));
+ knot_zone_contents_tree_apply_inorder(zone, node_dump_text, &param);
+ knot_zone_contents_nsec3_apply_inorder(zone, node_dump_text, &param);
+ fclose(f);
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/zone/zone-dump-text.h b/src/knot/zone/zone-dump-text.h
new file mode 100644
index 0000000..70dcff4
--- /dev/null
+++ b/src/knot/zone/zone-dump-text.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file zone-dump-text.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief Functions for dumping zone to text file.
+ *
+ * \addtogroup dnslib
+ * @{
+ */
+
+#ifndef _KNOT_ZONE_DUMP_TEXT_H_
+#define _KNOT_ZONE_DUMP_TEXT_H_
+
+#include "libknot/util/descriptor.h"
+#include "libknot/zone/zone.h"
+
+/*!
+ * \brief Dumps given zone to text (BIND-like) file.
+ *
+ * \param zone Zone to be saved.
+ * \param filename Name of file to be created.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EBADARG if the specified file is not valid for writing.
+ */
+int zone_dump_text(knot_zone_contents_t *zone, const char *filename);
+
+#endif // _KNOT_ZONE_DUMP_TEXT_H_
+
+/*! @} */
diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c
new file mode 100644
index 0000000..afc577d
--- /dev/null
+++ b/src/knot/zone/zone-dump.c
@@ -0,0 +1,2301 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "libknot/common.h"
+#include "knot/zone/zone-dump.h"
+#include "libknot/libknot.h"
+#include "knot/other/debug.h"
+#include "common/skip-list.h"
+#include "common/base32hex.h"
+#include "common/crc.h"
+#include "libknot/util/error.h"
+
+#define ZONECHECKS_VERBOSE
+
+/*! \note Contents of a dump file:
+ * MAGIC(knotxx) db_filename dname_table
+ * NUMBER_OF_NORMAL_NODES NUMBER_OF_NSEC3_NODES
+ * [normal_nodes] [nsec3_nodes]
+ * --------------------------------------------
+ * dname_table is dumped as follows:
+ * NUMBER_OF_DNAMES [dname_wire_length dname_wire label_count dname_labels ID]
+ * node has following format:
+ * owner_id
+ * node_flags node_rrset_count [node_rrsets]
+ * rrset has following format:
+ * rrset_type rrset_class rrset_ttl rrset_rdata_count rrset_rrsig_count
+ * [rrset_rdata] [rrset_rrsigs]
+ * rdata can contain either dname ID,
+ * or raw data stored like this: data_len [data]
+ */
+
+static const uint MAX_CNAME_CYCLE_DEPTH = 15;
+
+/*!
+ *\brief Internal error constants. General errors are added for convenience,
+ * so that code does not have to change if new errors are added.
+ */
+enum zonechecks_errors {
+ ZC_ERR_ALLOC = -40,
+ ZC_ERR_UNKNOWN,
+
+ ZC_ERR_MISSING_SOA,
+
+ ZC_ERR_GENERIC_GENERAL_ERROR, /* isn't there a better name? */
+
+ ZC_ERR_RRSIG_RDATA_TYPE_COVERED,
+ ZC_ERR_RRSIG_RDATA_TTL,
+ ZC_ERR_RRSIG_RDATA_LABELS,
+ ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER,
+ ZC_ERR_RRSIG_RDATA_SIGNED_WRONG,
+ ZC_ERR_RRSIG_NO_RRSIG,
+ ZC_ERR_RRSIG_SIGNED,
+ ZC_ERR_RRSIG_OWNER,
+ ZC_ERR_RRSIG_CLASS,
+ ZC_ERR_RRSIG_TTL,
+ ZC_ERR_RRSIG_NOT_ALL,
+
+ ZC_ERR_RRSIG_GENERAL_ERROR,
+
+ ZC_ERR_NO_NSEC,
+ ZC_ERR_NSEC_RDATA_BITMAP,
+ ZC_ERR_NSEC_RDATA_MULTIPLE,
+ ZC_ERR_NSEC_RDATA_CHAIN,
+ ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC,
+
+ ZC_ERR_NSEC_GENERAL_ERROR,
+
+ ZC_ERR_NSEC3_UNSECURED_DELEGATION,
+ ZC_ERR_NSEC3_NOT_FOUND,
+ ZC_ERR_NSEC3_UNSECURED_DELEGATION_OPT,
+ ZC_ERR_NSEC3_RDATA_TTL,
+ ZC_ERR_NSEC3_RDATA_CHAIN,
+ ZC_ERR_NSEC3_RDATA_BITMAP,
+
+ ZC_ERR_NSEC3_GENERAL_ERROR,
+
+ ZC_ERR_CNAME_CYCLE,
+ ZC_ERR_DNAME_CYCLE,
+ ZC_ERR_CNAME_EXTRA_RECORDS,
+ ZC_ERR_DNAME_EXTRA_RECORDS,
+ ZC_ERR_CNAME_EXTRA_RECORDS_DNSSEC,
+ ZC_ERR_CNAME_MULTIPLE,
+ ZC_ERR_DNAME_MULTIPLE,
+
+ ZC_ERR_CNAME_GENERAL_ERROR,
+
+ ZC_ERR_GLUE_NODE,
+ ZC_ERR_GLUE_RECORD,
+
+ ZC_ERR_GLUE_GENERAL_ERROR,
+};
+
+static char *error_messages[(-ZC_ERR_ALLOC) + 1] = {
+ [-ZC_ERR_ALLOC] = "Memory allocation error!\n",
+
+ [-ZC_ERR_MISSING_SOA] = "SOA record missing in zone!\n",
+
+ [-ZC_ERR_RRSIG_RDATA_TYPE_COVERED] =
+ "RRSIG: Type covered rdata field is wrong!\n",
+ [-ZC_ERR_RRSIG_RDATA_TTL] =
+ "RRSIG: TTL rdata field is wrong!\n",
+ [-ZC_ERR_RRSIG_RDATA_LABELS] =
+ "RRSIG: Labels rdata field is wrong!\n",
+ [-ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER] =
+ "RRSIG: Signer name is different than in DNSKEY!\n",
+ [-ZC_ERR_RRSIG_RDATA_SIGNED_WRONG] =
+ "RRSIG: Key error!\n",
+ [-ZC_ERR_RRSIG_NO_RRSIG] =
+ "RRSIG: No RRSIG!\n",
+ [-ZC_ERR_RRSIG_SIGNED] =
+ "RRSIG: Signed RRSIG!\n",
+ [-ZC_ERR_RRSIG_OWNER] =
+ "RRSIG: Owner name rdata field is wrong!\n",
+ [-ZC_ERR_RRSIG_CLASS] =
+ "RRSIG: Class is wrong!\n",
+ [-ZC_ERR_RRSIG_TTL] =
+ "RRSIG: TTL is wrong!\n",
+ [-ZC_ERR_RRSIG_NOT_ALL] =
+ "RRSIG: Not all RRs are signed!\n",
+
+ [-ZC_ERR_NO_NSEC] =
+ "NSEC: Missing NSEC record\n",
+ [-ZC_ERR_NSEC_RDATA_BITMAP] =
+ "NSEC: Wrong NSEC bitmap!\n",
+ [-ZC_ERR_NSEC_RDATA_MULTIPLE] =
+ "NSEC: Multiple NSEC records!\n",
+ [-ZC_ERR_NSEC_RDATA_CHAIN] =
+ "NSEC: NSEC chain is not coherent!\n",
+ [-ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC] =
+ "NSEC: NSEC chain is not cyclic!\n",
+
+ [-ZC_ERR_NSEC3_UNSECURED_DELEGATION] =
+ "NSEC3: Zone contains unsecured delegation!\n",
+ [-ZC_ERR_NSEC3_NOT_FOUND] =
+ "NSEC3: Could not find previous NSEC3 record in the zone!\n",
+ [-ZC_ERR_NSEC3_UNSECURED_DELEGATION_OPT] =
+ "NSEC3: Unsecured delegation is not part "
+ "of the Opt-Out span!\n",
+ [-ZC_ERR_NSEC3_RDATA_TTL] =
+ "NSEC3: Original TTL rdata field is wrong!\n",
+ [-ZC_ERR_NSEC3_RDATA_CHAIN] =
+ "NSEC3: NSEC3 chain is not coherent!\n",
+ [-ZC_ERR_NSEC3_RDATA_BITMAP] =
+ "NSEC3: NSEC3 bitmap error!\n",
+
+ [-ZC_ERR_CNAME_CYCLE] =
+ "CNAME: CNAME cycle!\n",
+ [-ZC_ERR_DNAME_CYCLE] =
+ "CNAME: DNAME cycle!\n",
+ [-ZC_ERR_CNAME_EXTRA_RECORDS] =
+ "CNAME: Node with CNAME record has other records!\n",
+ [-ZC_ERR_DNAME_EXTRA_RECORDS] =
+ "DNAME: Node with DNAME record has other records!\n",
+ [-ZC_ERR_CNAME_EXTRA_RECORDS_DNSSEC] =
+ "CNAME: Node with CNAME record has other "
+ "records than RRSIG and NSEC/NSEC3!\n",
+ [-ZC_ERR_CNAME_MULTIPLE] = "CNAME: Multiple CNAME records!\n",
+ [-ZC_ERR_DNAME_MULTIPLE] = "DNAME: Multiple DNAME records!\n",
+
+ /* ^
+ | Important errors (to be logged on first occurence and counted) */
+
+
+ /* Below are errors of lesser importance, to be counted unless
+ specified otherwise */
+
+ [-ZC_ERR_GLUE_NODE] =
+ "GLUE: Node with Glue record missing!\n",
+ [-ZC_ERR_GLUE_RECORD] =
+ "GLUE: Record with Glue address missing\n",
+};
+
+/*!
+ * \brief Structure representing handle options.
+ */
+struct handler_options {
+ char log_cname; /*!< Log all CNAME related semantic errors. */
+ char log_glue; /*!< Log all glue related semantic errors. */
+ char log_rrsigs; /*!< Log all RRSIG related semantic errors. */
+ char log_nsec; /*!< Log all NSEC related semantic errors. */
+ char log_nsec3; /*!< Log all NSEC3 related semantic errors. */
+};
+
+/*!
+ * \brief Structure for handling semantic errors.
+ */
+struct err_handler {
+ /* Consider moving error messages here */
+ struct handler_options options; /*!< Handler options. */
+ uint errors[(-ZC_ERR_ALLOC) + 1]; /*!< Array with error messages */
+};
+
+typedef struct err_handler err_handler_t;
+
+/*!
+ * \brief Creates new semantic error handler.
+ *
+ * \param log_cname If true, log all CNAME related events.
+ * \param log_glue If true, log all Glue related events.
+ * \param log_rrsigs If true, log all RRSIGs related events.
+ * \param log_nsec If true, log all NSEC related events.
+ * \param log_nsec3 If true, log all NSEC3 related events.
+ *
+ * \return err_handler_t * Created error handler.
+ */
+static err_handler_t *handler_new(char log_cname, char log_glue,
+ char log_rrsigs, char log_nsec,
+ char log_nsec3)
+{
+ err_handler_t *handler = malloc(sizeof(err_handler_t));
+ CHECK_ALLOC_LOG(handler, NULL);
+
+ /* It should be initialized, but to be safe */
+ memset(handler->errors, 0, sizeof(uint) * (-ZC_ERR_ALLOC + 1));
+
+ handler->options.log_cname = log_cname;
+ handler->options.log_glue = log_glue;
+ handler->options.log_rrsigs = log_rrsigs;
+ handler->options.log_nsec = log_nsec;
+ handler->options.log_nsec3 = log_nsec3;
+
+ return handler;
+}
+
+/*!
+ * \brief Prints error message with node information.
+ *
+ * \note If \a node is NULL, only total number of errors is printed.
+ *
+ * \param handler Error handler.
+ * \param node Node with semantic error in it.
+ * \param error Type of error.
+ */
+static void log_error_from_node(err_handler_t *handler,
+ const knot_node_t *node,
+ uint error)
+{
+ if (node != NULL) {
+ char *name =
+ knot_dname_to_str(knot_node_owner(node));
+ fprintf(stderr, "Semantic warning in node: %s: ", name);
+ fprintf(stderr, "%s", error_messages[-error]);
+ free(name);
+ } else {
+ fprintf(stderr, "Total number of warnings is: %d for error: %s",
+ handler->errors[-error],
+ error_messages[-error]);
+ }
+}
+
+/*!
+ * \brief Called when error has been encountered in node. Will either log error
+ * or print it, depending on handler's options.
+ *
+ * \param handler Error handler.
+ * \param node Node with semantic error in it.
+ * \param error Type of error.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval ZC_ERR_UNKNOWN if unknown error.
+ * \retval ZC_ERR_ALLOC if memory error.
+ */
+static int err_handler_handle_error(err_handler_t *handler,
+ const knot_node_t *node,
+ uint error)
+{
+ assert(handler && node);
+ if ((error != 0) &&
+ (error > ZC_ERR_GLUE_GENERAL_ERROR)) {
+ return ZC_ERR_UNKNOWN;
+ }
+
+ if (error == ZC_ERR_ALLOC) {
+ ERR_ALLOC_FAILED;
+ return ZC_ERR_ALLOC;
+ }
+
+ /* missing SOA can only occur once, so there
+ * needn't to be an option for it */
+
+ if ((error != 0) &&
+ (error < ZC_ERR_GENERIC_GENERAL_ERROR)) {
+ /* The two errors before SOA were handled */
+ log_error_from_node(handler, node, error);
+
+ } else if ((error < ZC_ERR_RRSIG_GENERAL_ERROR) &&
+ ((handler->errors[-error] == 0) ||
+ (handler->options.log_rrsigs))) {
+
+ log_error_from_node(handler, node, error);
+
+ } else if ((error > ZC_ERR_RRSIG_GENERAL_ERROR) &&
+ (error < ZC_ERR_NSEC_GENERAL_ERROR) &&
+ ((handler->errors[-error] == 0) ||
+ (handler->options.log_nsec))) {
+
+ log_error_from_node(handler, node, error);
+
+ } else if ((error > ZC_ERR_NSEC_GENERAL_ERROR) &&
+ (error < ZC_ERR_NSEC3_GENERAL_ERROR) &&
+ ((handler->errors[-error] == 0) ||
+ (handler->options.log_nsec3))) {
+
+ log_error_from_node(handler, node, error);
+
+ } else if ((error > ZC_ERR_NSEC3_GENERAL_ERROR) &&
+ (error < ZC_ERR_CNAME_GENERAL_ERROR) &&
+ ((handler->errors[-error] == 0) ||
+ (handler->options.log_cname))) {
+
+ log_error_from_node(handler, node, error);
+
+ } else if ((error > ZC_ERR_CNAME_GENERAL_ERROR) &&
+ (error < ZC_ERR_GLUE_GENERAL_ERROR) &&
+ handler->options.log_glue) {
+
+ log_error_from_node(handler, node, error);
+
+ }
+
+ handler->errors[-error]++;
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief This function prints all errors that occured in zone.
+ *
+ * \param handler Error handler containing found errors.
+ */
+static void err_handler_log_all(err_handler_t *handler)
+{
+ if (handler == NULL) {
+ return;
+ }
+
+ for (int i = ZC_ERR_ALLOC; i < ZC_ERR_GLUE_GENERAL_ERROR; i++) {
+ if (handler->errors[-i] > 0) {
+ log_error_from_node(handler, NULL, i);
+ }
+ }
+}
+
+/*!
+ * \brief Arguments to be used with tree traversal functions. Uses void pointers
+ * to be more versatile.
+ *
+ */
+struct arg {
+ void *arg1; /* FILE *f / zone */
+ void *arg2; /* skip_list_t */
+ void *arg3; /* zone */
+ void *arg4; /* first node */
+ void *arg5; /* last node */
+ void *arg6; /* error handler */
+ void *arg7; /* CRC */
+};
+
+typedef struct arg arg_t;
+
+/*!
+ * \brief Semantic check - CNAME cycles. Uses constant value with maximum
+ * allowed CNAME chain depth.
+ *
+ * \param zone Zone containing the RRSet.
+ * \param rrset RRSet to be tested.
+ *
+ * \retval KNOT_EOK when there is no cycle.
+ * \retval ZC_ERR_CNAME_CYCLE when cycle is present.
+ */
+static int check_cname_cycles_in_zone(knot_zone_contents_t *zone,
+ const knot_rrset_t *rrset)
+{
+ const knot_rrset_t *next_rrset = rrset;
+ assert(rrset);
+ const knot_rdata_t *tmp_rdata = knot_rrset_rdata(next_rrset);
+ const knot_node_t *next_node = NULL;
+
+ uint i = 0;
+
+ assert(tmp_rdata);
+
+ const knot_dname_t *next_dname =
+ knot_rdata_cname_name(tmp_rdata);
+
+ assert(next_dname);
+
+ while (i < MAX_CNAME_CYCLE_DEPTH && next_dname != NULL) {
+ next_node = knot_zone_contents_get_node(zone, next_dname);
+ if (next_node == NULL) {
+ next_node =
+ knot_zone_contents_get_nsec3_node(zone, next_dname);
+ }
+
+ if (next_node != NULL) {
+ next_rrset = knot_node_rrset(next_node,
+ KNOT_RRTYPE_CNAME);
+ if (next_rrset != NULL) {
+ next_dname =
+ knot_rdata_cname_name(next_rrset->rdata);
+ } else {
+ next_node = NULL;
+ next_dname = NULL;
+ }
+ } else {
+ next_dname = NULL;
+ }
+ i++;
+ }
+
+ /* even if the length is 0, i will be 1 */
+ if (i >= MAX_CNAME_CYCLE_DEPTH) {
+ return ZC_ERR_CNAME_CYCLE;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Return raw data from rdata item structure (without length).
+ *
+ * \param item Item to get rdata from.
+ * \return uint16_t * raw data without length.
+ */
+static inline uint16_t *rdata_item_data(const knot_rdata_item_t *item)
+{
+ return (uint16_t *)(item->raw_data + 1);
+}
+
+/*!
+ * \brief Returns type covered field from RRSIG RRSet's rdata.
+ *
+ * \param rdata RRSIG rdata.
+ * \return uint16_t Type covered.
+ */
+uint16_t type_covered_from_rdata(const knot_rdata_t *rdata)
+{
+ return ntohs(*(uint16_t *) rdata_item_data(&(rdata->items[0])));
+}
+
+/*!
+ * \brief Check whether DNSKEY rdata are valid.
+ *
+ * \param rdata DNSKEY rdata to be checked.
+ *
+ * \retval KNOT_EOK when rdata are OK.
+ * \retval ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER when rdata are not OK.
+ */
+static int check_dnskey_rdata(const knot_rdata_t *rdata)
+{
+ /* check that Zone key bit it set - position 7 in net order */
+ /*! \todo FIXME: endian? I swear I've fixed this already, it was 7 i guesss*/
+ uint16_t mask = 1 << 8; //0b0000000100000000;
+
+ uint16_t flags =
+ knot_wire_read_u16((uint8_t *)rdata_item_data
+ (knot_rdata_item(rdata, 0)));
+
+ if (flags & mask) {
+ return KNOT_EOK;
+ } else {
+ /* This error does not exactly fit, but it's better
+ * than a new one */
+ return ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER;
+ }
+}
+
+/*!
+ * \brief Calculates keytag for RSA/SHA algorithm.
+ *
+ * \param key Key wireformat.
+ * \param keysize Wireformat size.
+ *
+ * \return uint16_t Calculated keytag.
+ */
+static uint16_t keytag_1(uint8_t *key, uint16_t keysize)
+{
+ uint16_t ac = 0;
+ if (keysize > 4) {
+ memmove(&ac, key + keysize - 3, 2);
+ }
+
+ ac = ntohs(ac);
+ return ac;
+}
+
+/*!
+ * \brief Calculates keytag from key wire.
+ *
+ * \param key Key wireformat.
+ * \param keysize Wireformat size.
+ *
+ * \return uint16_t Calculated keytag.
+ */
+static uint16_t keytag(uint8_t *key, uint16_t keysize )
+{
+ uint32_t ac = 0; /* assumed to be 32 bits or larger */
+
+ /* algorithm RSA/SHA */
+ if (key[3] == 1) {
+ return keytag_1(key, keysize);
+ } else {
+ for(int i = 0; i < keysize; i++) {
+ ac += (i & 1) ? key[i] : key[i] << 8;
+ }
+
+ ac += (ac >> 16) & 0xFFFF;
+ return (uint16_t)ac & 0xFFFF;
+ }
+}
+
+/*!
+ * \brief Returns size of raw data item.
+ *
+ * \param item Raw data item.
+ *
+ * \return uint16_t Size of raw data item.
+ */
+static inline uint16_t rdata_item_size(const knot_rdata_item_t *item)
+{
+ return item->raw_data[0];
+}
+
+/*!
+ * \brief Converts DNSKEY rdata to wireformat.
+ *
+ * \param rdata DNSKEY rdata to be converted.
+ * \param wire Created wire.
+ * \param size Size of created wire.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_ENOMEM on memory error.
+ */
+static int dnskey_to_wire(const knot_rdata_t *rdata, uint8_t **wire,
+ uint *size)
+{
+ assert(*wire == NULL);
+ /* flags + algorithm + protocol + keysize */
+ *size = 2 + 1 + 1 + knot_rdata_item(rdata, 3)->raw_data[0];
+ *wire = malloc(sizeof(uint8_t) * *size);
+ CHECK_ALLOC_LOG(*wire, KNOT_ENOMEM);
+
+ /* copy the wire octet by octet */
+
+ /* TODO check if we really have that many items */
+ if (rdata->count < 4) {
+ return KNOT_ERROR;
+ }
+
+ (*wire)[0] = ((uint8_t *)(knot_rdata_item(rdata, 0)->raw_data))[2];
+ (*wire)[1] = ((uint8_t *)(knot_rdata_item(rdata, 0)->raw_data))[3];
+
+ (*wire)[2] = ((uint8_t *)(knot_rdata_item(rdata, 1)->raw_data))[2];
+ (*wire)[3] = ((uint8_t *)(knot_rdata_item(rdata, 2)->raw_data))[2];
+
+ memcpy(*wire + 4, knot_rdata_item(rdata, 3)->raw_data + 1,
+ knot_rdata_item(rdata, 3)->raw_data[0]);
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Semantic check - RRSIG rdata.
+ *
+ * \param rdata_rrsig RRSIG rdata to be checked.
+ * \param rrset RRSet containing the rdata.
+ * \param dnskey_rrset RRSet containing zone's DNSKEY
+ *
+ * \retval KNOT_EOK if rdata are OK.
+ *
+ * \return Appropriate error code if error was found.
+ */
+static int check_rrsig_rdata(const knot_rdata_t *rdata_rrsig,
+ const knot_rrset_t *rrset,
+ const knot_rrset_t *dnskey_rrset)
+{
+ if (rdata_rrsig == NULL) {
+ return ZC_ERR_RRSIG_NO_RRSIG;
+ }
+
+ if (type_covered_from_rdata(rdata_rrsig) !=
+ knot_rrset_type(rrset)) {
+ /* zoneparser would not let this happen
+ * but to be on the safe side
+ */
+ return ZC_ERR_RRSIG_RDATA_TYPE_COVERED;
+ }
+
+ /* label number at the 2nd index should be same as owner's */
+ uint16_t *raw_data =
+ rdata_item_data(knot_rdata_item(rdata_rrsig, 2));
+
+ uint8_t labels_rdata = ((uint8_t *)raw_data)[0];
+
+ int tmp = knot_dname_label_count(knot_rrset_owner(rrset)) -
+ labels_rdata;
+
+ if (tmp != 0) {
+ /* if name has wildcard, label must not be included */
+ if (!knot_dname_is_wildcard(knot_rrset_owner(rrset))) {
+ return ZC_ERR_RRSIG_RDATA_LABELS;
+ } else {
+ if (abs(tmp) != 1) {
+ return ZC_ERR_RRSIG_RDATA_LABELS;
+ }
+ }
+ }
+
+ /* check original TTL */
+ uint32_t original_ttl =
+ knot_wire_read_u32((uint8_t *)rdata_item_data(
+ knot_rdata_item(rdata_rrsig, 3)));
+
+ if (original_ttl != knot_rrset_ttl(rrset)) {
+ return ZC_ERR_RRSIG_RDATA_TTL;
+ }
+
+ /* signer's name is same as in the zone apex */
+ knot_dname_t *signer_name =
+ knot_rdata_item(rdata_rrsig, 7)->dname;
+
+ /* dnskey is in the apex node */
+ if (knot_dname_compare(signer_name,
+ knot_rrset_owner(dnskey_rrset)) != 0) {
+ return ZC_ERR_RRSIG_RDATA_DNSKEY_OWNER;
+ }
+
+ /* Compare algorithm, key tag and signer's name with DNSKEY rrset
+ * one of the records has to match. Signer name has been checked
+ * before */
+ char match = 0;
+ const knot_rdata_t *tmp_dnskey_rdata =
+ knot_rrset_rdata(dnskey_rrset);
+ do {
+ uint8_t alg =
+ ((uint8_t *)(knot_rdata_item(rdata_rrsig, 1)->raw_data))[2];
+ uint8_t alg_dnskey =
+ ((uint8_t *)(knot_rdata_item(tmp_dnskey_rdata,
+ 2)->raw_data))[2];
+
+ raw_data = rdata_item_data(knot_rdata_item(rdata_rrsig, 6));
+ uint16_t key_tag_rrsig =
+ knot_wire_read_u16((uint8_t *)raw_data);
+
+/* raw_data =
+ rdata_item_data(knot_rdata_item(
+ tmp_dnskey_rdata, 3));
+
+ uint16_t raw_length = rdata_item_size(knot_rdata_item(
+ tmp_dnskey_rdata, 3)); */
+
+ uint8_t *dnskey_wire = NULL;
+ uint dnskey_wire_size = 0;
+
+ int ret = 0;
+ if ((ret = dnskey_to_wire(tmp_dnskey_rdata, &dnskey_wire,
+ &dnskey_wire_size)) != KNOT_EOK) {
+ return ret;
+ }
+
+ uint16_t key_tag_dnskey =
+ keytag(dnskey_wire, dnskey_wire_size);
+
+ free(dnskey_wire);
+
+ match = (alg == alg_dnskey) &&
+ (key_tag_rrsig == key_tag_dnskey) &&
+ !check_dnskey_rdata(tmp_dnskey_rdata);
+
+ } while (!match &&
+ ((tmp_dnskey_rdata =
+ knot_rrset_rdata_next(dnskey_rrset,
+ tmp_dnskey_rdata))
+ != NULL));
+
+ if (!match) {
+ return ZC_ERR_RRSIG_RDATA_SIGNED_WRONG;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Semantic check - RRSet's RRSIG.
+ *
+ * \param rrset RRSet containing RRSIG.
+ * \param dnskey_rrset
+ * \param nsec3 NSEC3 active.
+ *
+ * \retval KNOT_EOK on success.
+ *
+ * \return Appropriate error code if error was found.
+ */
+static int check_rrsig_in_rrset(const knot_rrset_t *rrset,
+ const knot_rrset_t *dnskey_rrset,
+ char nsec3)
+{
+ assert(dnskey_rrset && rrset);
+
+ const knot_rrset_t *rrsigs = knot_rrset_rrsigs(rrset);
+
+ if (rrsigs == NULL) {
+ return ZC_ERR_RRSIG_NO_RRSIG;
+ }
+
+ /* signed rrsig - nonsense */
+ if (knot_rrset_rrsigs(rrsigs) != NULL) {
+ return ZC_ERR_RRSIG_SIGNED;
+ }
+
+ /* Different owner, class, ttl */
+
+ if (knot_dname_compare(knot_rrset_owner(rrset),
+ knot_rrset_owner(rrsigs)) != 0) {
+ return ZC_ERR_RRSIG_OWNER;
+ }
+
+ if (knot_rrset_class(rrset) != knot_rrset_class(rrsigs)) {
+ return ZC_ERR_RRSIG_CLASS;
+ }
+
+ if (knot_rrset_ttl(rrset) != knot_rrset_ttl(rrset)) {
+ return ZC_ERR_RRSIG_TTL;
+ }
+
+ /* Check whether all rrsets have their rrsigs */
+ const knot_rdata_t *tmp_rdata = knot_rrset_rdata(rrset);
+ const knot_rdata_t *tmp_rrsig_rdata = knot_rrset_rdata(rrsigs);
+
+ assert(tmp_rdata);
+ assert(tmp_rrsig_rdata);
+ int ret = 0;
+ char all_signed = tmp_rdata && tmp_rrsig_rdata;
+ do {
+ if ((ret = check_rrsig_rdata(tmp_rrsig_rdata,
+ rrset,
+ dnskey_rrset)) != 0) {
+ return ret;
+ }
+
+ all_signed = tmp_rdata && tmp_rrsig_rdata;
+ } while (((tmp_rdata = knot_rrset_rdata_next(rrset, tmp_rdata))
+ != NULL) &&
+ ((tmp_rrsig_rdata =
+ knot_rrset_rdata_next(rrsigs, tmp_rrsig_rdata))
+ != NULL));
+
+ if (!all_signed) {
+ return ZC_ERR_RRSIG_NOT_ALL;
+ }
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Returns bit on index from array in network order. Taken from NSD.
+ *
+ * \param bits Array in network order.
+ * \param index Index to return from array.
+ *
+ * \return int Bit on given index.
+ */
+static int get_bit(uint8_t *bits, size_t index)
+{
+ /*
+ * The bits are counted from left to right, so bit #0 is the
+ * leftmost bit.
+ */
+ return bits[index / 8] & (1 << (7 - index % 8));
+}
+
+/*!
+ * \brief Converts NSEC bitmap to array of integers. (Inspired by NSD code)
+ *
+ * \param item Item containing the bitmap.
+ * \param array Array to be created.
+ * \param count Count of items in array.
+ *
+ * \retval KNOT_OK on success.
+ * \retval KNOT_NOMEM on memory error.
+ */
+static int rdata_nsec_to_type_array(const knot_rdata_item_t *item,
+ uint16_t **array,
+ uint *count)
+{
+ assert(*array == NULL);
+
+ uint8_t *data = (uint8_t *)rdata_item_data(item);
+
+ int increment = 0;
+ *count = 0;
+
+ for (int i = 0; i < rdata_item_size(item); i += increment) {
+ increment = 0;
+ uint8_t window = data[i];
+ increment++;
+
+ uint8_t bitmap_size = data[i + increment];
+ increment++;
+
+ uint8_t *bitmap =
+ malloc(sizeof(uint8_t) * (bitmap_size));
+ if (bitmap == NULL) {
+ ERR_ALLOC_FAILED;
+ free(*array);
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(bitmap, data + i + increment,
+ bitmap_size);
+
+ increment += bitmap_size;
+
+ for (int j = 0; j < bitmap_size * 8; j++) {
+ if (get_bit(bitmap, j)) {
+ (*count)++;
+ void *tmp = realloc(*array,
+ sizeof(uint16_t) *
+ *count);
+ if (tmp == NULL) {
+ ERR_ALLOC_FAILED;
+ free(bitmap);
+ free(*array);
+ return KNOT_ENOMEM;
+ }
+ *array = tmp;
+ (*array)[*count - 1] = j + window * 256;
+ }
+ }
+ free(bitmap);
+ }
+
+ return KNOT_EOK;
+}
+
+/* should write error, not return values !!! */
+
+/*!
+ * \brief Semantic check - check node's NSEC node.
+ *
+ * \param zone Current zone.
+ * \param node Node to be checked.
+ * \param handler Error handler
+ *
+ * \retval KNOT_EOK if no error was found.
+ *
+ * \return Appropriate error code if error was found.
+ */
+static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, knot_node_t *node,
+ err_handler_t *handler)
+{
+ assert(handler);
+ const knot_node_t *nsec3_node = knot_node_nsec3_node(node, 0);
+
+ if (nsec3_node == NULL) {
+ /* I know it's probably not what RFCs say, but it will have to
+ * do for now. */
+ if (knot_node_rrset(node, KNOT_RRTYPE_DS) != NULL) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_NSEC3_UNSECURED_DELEGATION);
+ } else {
+ /* Unsecured delegation, check whether it is part of
+ * opt-out span */
+ const knot_node_t *nsec3_previous;
+ const knot_node_t *nsec3_node;
+
+ if (knot_zone_contents_find_nsec3_for_name(zone,
+ knot_node_owner(node),
+ &nsec3_node,
+ &nsec3_previous, 0) != 0) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_NSEC3_NOT_FOUND);
+ }
+
+ if (nsec3_node == NULL) {
+ /* Probably should not ever happen */
+ return ZC_ERR_NSEC3_NOT_FOUND;
+ }
+
+ assert(nsec3_previous);
+
+ const knot_rrset_t *previous_rrset =
+ knot_node_rrset(nsec3_previous,
+ KNOT_RRTYPE_NSEC3);
+
+ assert(previous_rrset);
+
+ /* check for Opt-Out flag */
+ uint8_t flags =
+ ((uint8_t *)(previous_rrset->rdata->items[1].raw_data))[2];
+
+ uint8_t opt_out_mask = 1;
+
+ if (!(flags & opt_out_mask)) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_NSEC3_UNSECURED_DELEGATION_OPT);
+ }
+ }
+ }
+
+ const knot_rrset_t *nsec3_rrset =
+ knot_node_rrset(nsec3_node, KNOT_RRTYPE_NSEC3);
+
+ assert(nsec3_rrset);
+
+ const knot_rrset_t *soa_rrset =
+ knot_node_rrset(knot_zone_contents_apex(zone),
+ KNOT_RRTYPE_SOA);
+ assert(soa_rrset);
+
+ uint32_t minimum_ttl =
+ knot_wire_read_u32((uint8_t *)
+ rdata_item_data(
+ knot_rdata_item(
+ knot_rrset_rdata(
+ knot_node_rrset(
+ knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA)), 6)));
+ /* Are those getters even worth this?
+ * Now I have no idea what this code does. */
+
+ if (knot_rrset_ttl(nsec3_rrset) != minimum_ttl) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_NSEC3_RDATA_TTL);
+ }
+
+ /* check that next dname is in the zone */
+ uint8_t *next_dname_decoded = NULL;
+ size_t real_size = 0;
+
+ if (((real_size = base32hex_encode_alloc(((char *)
+ rdata_item_data(&(nsec3_rrset->rdata->items[4]))) + 1,
+ rdata_item_size(&nsec3_rrset->rdata->items[4]) - 1,
+ (char **)&next_dname_decoded)) <= 0) ||
+ (next_dname_decoded == NULL)) {
+ fprintf(stderr, "Could not encode base32 string!\n");
+ return KNOT_ERROR;
+ }
+
+ /* This is why we allocate maximum length of decoded string + 1 */
+ memmove(next_dname_decoded + 1, next_dname_decoded, real_size);
+ next_dname_decoded[0] = real_size;
+
+ /* Local allocation, will be discarded. */
+ knot_dname_t *next_dname =
+ knot_dname_new_from_wire(next_dname_decoded,
+ real_size + 1, NULL);
+ CHECK_ALLOC_LOG(next_dname, KNOT_ENOMEM);
+
+ free(next_dname_decoded);
+
+ if (knot_dname_cat(next_dname,
+ knot_node_owner(knot_zone_contents_apex(zone))) == NULL) {
+ fprintf(stderr, "Could not concatenate dnames!\n");
+ return KNOT_ERROR;
+
+ }
+
+ if (knot_zone_contents_find_nsec3_node(zone, next_dname) == NULL) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_NSEC3_RDATA_CHAIN);
+ }
+
+ /* Directly discard. */
+ knot_dname_free(&next_dname);
+
+ /* This is probably not sufficient, but again, it is covered in
+ * zone load time */
+
+ uint count;
+ uint16_t *array = NULL;
+ if (rdata_nsec_to_type_array(
+ knot_rdata_item(
+ knot_rrset_rdata(nsec3_rrset), 5),
+ &array, &count) != 0) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_ALLOC);
+ return KNOT_ERROR;
+ }
+
+ uint16_t type = 0;
+ for (int j = 0; j < count; j++) {
+ /* test for each type's presence */
+ type = array[j];
+ if (type == KNOT_RRTYPE_RRSIG) {
+ continue;
+ }
+ if (knot_node_rrset(node,
+ type) == NULL) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_NSEC3_RDATA_BITMAP);
+ break;
+/* char *name =
+ knot_dname_to_str(
+ log_zone_error("Node %s does "
+ "not contain RRSet of type %s "
+ "but NSEC bitmap says "
+ "it does!\n", name,
+ knot_rrtype_to_string(type));
+ free(name); */
+ }
+ }
+
+ free(array);
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Run semantic checks for node without DNSSEC-related types.
+ *
+ * \param zone Current zone.
+ * \param node Node to be checked.
+ * \param do_checks Level of checks to be done.
+ * \param handler Error handler.
+ *
+ * \retval KNOT_EOK if no error was found.
+ *
+ * \return Appropriate error code if error was found.
+ */
+static int semantic_checks_plain(knot_zone_contents_t *zone,
+ knot_node_t *node,
+ char do_checks,
+ err_handler_t *handler)
+{
+ assert(handler);
+ const knot_rrset_t *cname_rrset =
+ knot_node_rrset(node, KNOT_RRTYPE_CNAME);
+ if (cname_rrset != NULL) {
+ if (check_cname_cycles_in_zone(zone, cname_rrset) !=
+ KNOT_EOK) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_CNAME_CYCLE);
+ }
+
+ /* No DNSSEC and yet there is more than one rrset in node */
+ if (do_checks == 1 &&
+ knot_node_rrset_count(node) != 1) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_CNAME_EXTRA_RECORDS);
+ } else if (knot_node_rrset_count(node) != 1) {
+ /* With DNSSEC node can contain RRSIG or NSEC */
+ if (!(knot_node_rrset(node, KNOT_RRTYPE_RRSIG) ||
+ knot_node_rrset(node, KNOT_RRTYPE_NSEC)) ||
+ knot_node_rrset_count(node) > 3) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_CNAME_EXTRA_RECORDS_DNSSEC);
+ }
+ }
+
+ if (knot_rrset_rdata(cname_rrset)->next !=
+ knot_rrset_rdata(cname_rrset)) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_CNAME_MULTIPLE);
+ }
+ }
+
+ const knot_rrset_t *dname_rrset =
+ knot_node_rrset(node, KNOT_RRTYPE_DNAME);
+ if (dname_rrset != NULL) {
+ if (check_cname_cycles_in_zone(zone, dname_rrset) !=
+ KNOT_EOK) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_DNAME_CYCLE);
+ }
+
+ if (knot_node_rrset(node, KNOT_RRTYPE_CNAME)) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_DNAME_EXTRA_RECORDS);
+ }
+
+ if (knot_rrset_rdata(dname_rrset)->next !=
+ knot_rrset_rdata(dname_rrset)) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_DNAME_MULTIPLE);
+ }
+ }
+
+ /* check for glue records at zone cuts */
+ if (knot_node_is_deleg_point(node)) {
+ const knot_rrset_t *ns_rrset =
+ knot_node_rrset(node, KNOT_RRTYPE_NS);
+ assert(ns_rrset);
+ //FIXME this should be an error as well ! (i guess)
+
+ const knot_dname_t *ns_dname =
+ knot_rdata_get_item(knot_rrset_rdata
+ (ns_rrset), 0)->dname;
+
+ assert(ns_dname);
+
+ const knot_node_t *glue_node =
+ knot_zone_contents_find_node(zone, ns_dname);
+
+ if (knot_dname_is_subdomain(ns_dname,
+ knot_node_owner(knot_zone_contents_apex(zone)))) {
+ if (glue_node == NULL) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_GLUE_NODE);
+ } else {
+ if ((knot_node_rrset(glue_node,
+ KNOT_RRTYPE_A) == NULL) &&
+ (knot_node_rrset(glue_node,
+ KNOT_RRTYPE_AAAA) == NULL)) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_GLUE_RECORD);
+ }
+ }
+ }
+ }
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Run semantic checks for node without DNSSEC-related types.
+ *
+ * \param zone Current zone.
+ * \param node Node to be checked.
+ * \param first_node First node in canonical order.
+ * \param last_node Last node in canonical order.
+ * \param handler Error handler.
+ * \param nsec3 NSEC3 used.
+ *
+ * \retval KNOT_EOK if no error was found.
+ *
+ * \return Appropriate error code if error was found.
+ */
+static int semantic_checks_dnssec(knot_zone_contents_t *zone,
+ knot_node_t *node,
+ knot_node_t *first_node,
+ knot_node_t **last_node,
+ err_handler_t *handler,
+ char nsec3)
+{
+ assert(handler);
+ assert(node);
+ char auth = !knot_node_is_non_auth(node);
+ char deleg = knot_node_is_deleg_point(node);
+ uint rrset_count = knot_node_rrset_count(node);
+ const knot_rrset_t **rrsets = knot_node_rrsets(node);
+ const knot_rrset_t *dnskey_rrset =
+ knot_node_rrset(knot_zone_contents_apex(zone),
+ KNOT_RRTYPE_DNSKEY);
+
+ int ret = 0;
+
+ for (int i = 0; i < rrset_count; i++) {
+ const knot_rrset_t *rrset = rrsets[i];
+ if (auth && !deleg &&
+ (ret = check_rrsig_in_rrset(rrset, dnskey_rrset,
+ nsec3)) != 0) {
+ /* CLEANUP */
+/* log_zone_error("RRSIG %d node %s\n", ret,
+ knot_dname_to_str(node->owner));*/
+
+ err_handler_handle_error(handler, node, ret);
+ }
+
+ if (!nsec3 && auth) {
+ /* check for NSEC record */
+ const knot_rrset_t *nsec_rrset =
+ knot_node_rrset(node,
+ KNOT_RRTYPE_NSEC);
+
+ if (nsec_rrset == NULL) {
+ err_handler_handle_error(handler, node,
+ ZC_ERR_NO_NSEC);
+ /* CLEANUP */
+/* char *name =
+ knot_dname_to_str(node->owner);
+ log_zone_error("Missing NSEC in node: "
+ "%s\n", name);
+ free(name);
+ return; */
+ } else {
+
+ /* check NSEC/NSEC3 bitmap */
+
+ uint count;
+
+ uint16_t *array = NULL;
+
+ if (rdata_nsec_to_type_array(
+ knot_rdata_item(
+ knot_rrset_rdata(nsec_rrset),
+ 1),
+ &array, &count) != 0) {
+ err_handler_handle_error(handler,
+ NULL,
+ ZC_ERR_ALLOC);
+ return ZC_ERR_ALLOC; /* ... */
+ /*return; */
+ }
+
+ uint16_t type = 0;
+ for (int j = 0; j < count; j++) {
+ /* test for each type's presence */
+ type = array[j];
+ if (type == KNOT_RRTYPE_RRSIG) {
+ continue;
+ }
+ if (knot_node_rrset(node,
+ type) == NULL) {
+ err_handler_handle_error(
+ handler,
+ node,
+ ZC_ERR_NSEC_RDATA_BITMAP);
+ /* CLEANUP */
+ /* char *name =
+ knot_dname_to_str(
+ knot_node_owner(node));
+
+ log_zone_error("Node %s does "
+ "not contain RRSet of type %s "
+ "but NSEC bitmap says "
+ "it does!\n", name,
+ knot_rrtype_to_string(type));
+
+ free(name); */
+ }
+ }
+ free(array);
+ }
+
+ /* Test that only one record is in the
+ * NSEC RRSet */
+
+ if ((nsec_rrset != NULL) &&
+ knot_rrset_rdata(nsec_rrset)->next !=
+ knot_rrset_rdata(nsec_rrset)) {
+ err_handler_handle_error(handler,
+ node,
+ ZC_ERR_NSEC_RDATA_MULTIPLE);
+ /* CLEANUP */
+/* char *name =
+ knot_dname_to_str(
+ knot_node_owner(node));
+ log_zone_error("Node %s contains more "
+ "than one NSEC "
+ "record!\n", name);
+ knot_rrset_dump(nsec_rrset, 0);
+ free(name); */
+ }
+
+ /*
+ * Test that NSEC chain is coherent.
+ * We have already checked that every
+ * authoritative node contains NSEC record
+ * so checking should only be matter of testing
+ * the next link in each node.
+ */
+
+ if (nsec_rrset != NULL) {
+ knot_dname_t *next_domain =
+ knot_rdata_item(
+ knot_rrset_rdata(nsec_rrset),
+ 0)->dname;
+
+ assert(next_domain);
+
+ if (knot_zone_contents_find_node(zone, next_domain) ==
+ NULL) {
+ err_handler_handle_error(handler,
+ node,
+ ZC_ERR_NSEC_RDATA_CHAIN);
+ /* CLEANUP */
+/* log_zone_error("NSEC chain is not "
+ "coherent!\n"); */
+ }
+
+ if (knot_dname_compare(next_domain,
+ knot_node_owner(knot_zone_contents_apex(zone)))
+ == 0) {
+ /* saving the last node */
+ *last_node = node;
+ }
+
+ }
+ } else if (nsec3 && (auth || deleg)) { /* nsec3 */
+ int ret = check_nsec3_node_in_zone(zone, node,
+ handler);
+ if (ret != KNOT_EOK) {
+ free(rrsets);
+ return ret;
+ }
+ }
+ }
+ free(rrsets);
+
+ return KNOT_EOK;
+}
+
+/*!
+ * \brief Function called by zone traversal function. Used to call
+ * knot_zone_save_enclosers.
+ *
+ * \param node Node to be searched.
+ * \param data Arguments.
+ */
+static void do_checks_in_tree(knot_node_t *node, void *data)
+{
+ assert(data != NULL);
+ arg_t *args = (arg_t *)data;
+
+ knot_rrset_t **rrsets = knot_node_get_rrsets(node);
+ short count = knot_node_rrset_count(node);
+
+ assert(count == 0 || rrsets != NULL);
+
+ knot_zone_contents_t *zone = (knot_zone_contents_t *)args->arg1;
+
+ assert(zone);
+
+
+/* for (int i = 0; i < count; ++i) {
+ assert(rrsets[i] != NULL);
+ knot_zone_save_enclosers_rrset(rrsets[i],
+ zone,
+ (skip_list_t *)args->arg2);
+ } */
+
+ knot_node_t *first_node = (knot_node_t *)args->arg4;
+ knot_node_t **last_node = (knot_node_t **)args->arg5;
+
+ err_handler_t *handler = (err_handler_t *)args->arg6;
+
+ char do_checks = *((char *)(args->arg3));
+
+ if (do_checks) {
+ semantic_checks_plain(zone, node, do_checks, handler);
+ }
+
+ if (do_checks > 1) {
+ semantic_checks_dnssec(zone, node, first_node, last_node,
+ handler, do_checks == 3);
+ }
+
+ free(rrsets);
+}
+
+/*!
+ * \brief Helper function - wraps its arguments into arg_t structure and
+ * calls function that does the actual work.
+ *
+ * \param zone Zone to be searched / checked
+ * \param list Skip list of closests enclosers.
+ * \param do_checks Level of semantic checks.
+ * \param handler Semantic error handler.
+ * \param last_node Last checked node, which is part of NSEC(3) chain.
+ */
+void zone_do_sem_checks(knot_zone_contents_t *zone, char do_checks,
+ err_handler_t *handler,
+ knot_node_t **last_node)
+{
+ if (!do_checks) {
+ return;
+ }
+
+ arg_t arguments;
+ arguments.arg1 = zone;
+ arguments.arg3 = &do_checks;
+ arguments.arg4 = NULL;
+ arguments.arg5 = last_node;
+ arguments.arg6 = handler;
+
+ knot_zone_contents_tree_apply_inorder(zone,
+ do_checks_in_tree,
+ (void *)&arguments);
+}
+
+static inline int fwrite_to_file_crc(const void *src,
+ size_t size, size_t n, FILE *f,
+ crc_t *crc)
+{
+ size_t rc = fwrite(src, size, n, f);
+ if (rc != n) {
+ fprintf(stderr, "fwrite: invalid write %zu (expected %zu)\n", rc,
+ n);
+ }
+ /* \todo this seems to be wrong, if you fwrite less than n items, you probably should not continue */
+
+ if (size * n > 0) {
+ *crc =
+ crc_update(*crc, (unsigned char *)src,
+ size * n);
+ }
+
+ /* \todo the rc return is certainly wrong as it is used in the caller function */
+// return rc == n;
+ return (int)rc;
+
+}
+
+static inline int fwrite_to_stream(const void *src,
+ size_t size, size_t n,
+ uint8_t **stream,
+ size_t *stream_size)
+{
+ /* Resize the stream */
+ void *tmp = realloc(*stream,
+ (*stream_size + (size * n)) * sizeof(uint8_t));
+ if (tmp != NULL) {
+ *stream = tmp;
+ memcpy(*stream + *stream_size, src,
+ size * n);
+ *stream_size += (size * n) * sizeof(uint8_t);
+ return KNOT_EOK;
+ } else {
+ free(*stream);
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+static int fwrite_wrapper(const void *src,
+ size_t size, size_t n, FILE *fp,
+ uint8_t **stream, size_t *stream_size, crc_t *crc)
+{
+ if (fp == NULL) {
+ assert(stream && stream_size);
+ assert(crc == NULL);
+ return fwrite_to_stream(src, size, n, stream, stream_size);
+ } else {
+ assert(stream == NULL && stream_size == NULL);
+ return fwrite_to_file_crc(src, size, n, fp, crc);
+ }
+}
+
+/*!
+ * \brief Dumps dname labels in binary format to given file.
+ *
+ * \param dname Dname whose labels are to be dumped.
+ * \param f Output file.
+ */
+static void knot_labels_dump_binary(const knot_dname_t *dname, FILE *f,
+ uint8_t **stream, size_t *stream_size,
+ crc_t *crc)
+{
+ dbg_zdump("label count: %d\n", dname->label_count);
+ uint16_t label_count = dname->label_count;
+ /* \todo check the return value */
+ fwrite_wrapper(&label_count, sizeof(label_count), 1, f, stream,
+ stream_size, crc);
+ /* \todo check the return value */
+ fwrite_wrapper(dname->labels, sizeof(uint8_t), dname->label_count, f,
+ stream, stream_size, crc);
+}
+
+/*!
+ * \brief Dumps dname in binary format to given file.
+ *
+ * \param dname Dname to be dumped.
+ * \param f Output file.
+ */
+static void knot_dname_dump_binary(const knot_dname_t *dname, FILE *f,
+ uint8_t **stream, size_t *stream_size,
+ crc_t *crc)
+{
+ uint32_t dname_size = dname->size;
+ /* \todo check the return value */
+ fwrite_wrapper(&dname_size, sizeof(dname_size), 1, f, stream,
+ stream_size, crc);
+ /* \todo check the return value */
+ fwrite_wrapper(dname->name, sizeof(uint8_t), dname->size, f,
+ stream, stream_size, crc);
+ dbg_zdump("dname size: %d\n", dname->size);
+ knot_labels_dump_binary(dname, f, stream, stream_size, crc);
+}
+
+/*!< \todo some global variable indicating error! */
+static void dump_dname_with_id(const knot_dname_t *dname, FILE *f,
+ uint8_t **stream, size_t *stream_size,
+ crc_t *crc)
+{
+ uint32_t id = dname->id;
+ /* \todo check the return value */
+ fwrite_wrapper(&id, sizeof(id), 1, f, stream, stream_size, crc);
+ knot_dname_dump_binary(dname, f, stream, stream_size, crc);
+/* if (!fwrite_wrapper_safe(&dname->id, sizeof(dname->id), 1, f)) {
+ return KNOT_ERROR;
+ } */
+}
+
+/*!
+ * \brief Dumps given rdata in binary format to given file.
+ *
+ * \param rdata Rdata to be dumped.
+ * \param type Type of rdata.
+ * \param data Arguments to be propagated.
+ */
+static void knot_rdata_dump_binary(knot_rdata_t *rdata,
+ uint32_t type, void *data, int use_ids,
+ uint8_t **stream, size_t *stream_size,
+ crc_t *crc)
+{
+ FILE *f = (FILE *)((arg_t *)data)->arg1;
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ assert(desc != NULL);
+
+ dbg_zdump("Dumping type: %d\n", type);
+
+ if (desc->fixed_items) {
+ assert(desc->length == rdata->count);
+ }
+
+ /* Write rdata count. */
+ /* \todo check the return value */
+ fwrite_wrapper(&(rdata->count),
+ sizeof(rdata->count), 1, f, stream, stream_size, crc);
+
+ for (int i = 0; i < rdata->count; i++) {
+ if (&(rdata->items[i]) == NULL) {
+ dbg_zdump("Item n. %d is not set!\n", i);
+ continue;
+ }
+ dbg_zdump("Item n: %d\n", i);
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) {
+ /* some temp variables - this is way too long */
+ assert(rdata->items[i].dname != NULL);
+ knot_dname_t *wildcard = NULL;
+
+ if (rdata->items[i].dname->node != NULL &&
+ rdata->items[i].dname->node->owner !=
+ rdata->items[i].dname) {
+ wildcard = rdata->items[i].dname->node->owner;
+ }
+
+ if (use_ids) {
+ /* Write ID. */
+ dbg_zload("%s \n",
+ knot_dname_to_str(rdata->items[i].dname));
+ assert(rdata->items[i].dname->id != 0);
+
+ uint32_t id = rdata->items[i].dname->id;
+ /* \todo check the return value */
+ fwrite_wrapper(&id,
+ sizeof(id), 1, f, stream, stream_size,
+ crc);
+ } else {
+// assert(rdata->items[i].dname->id != 0);
+ dump_dname_with_id(rdata->items[i].dname,
+ f, stream,
+ stream_size, crc);
+ }
+
+ /* Write in the zone bit */
+ if (rdata->items[i].dname->node != NULL && !wildcard) {
+ /* \todo check the return value */
+ fwrite_wrapper((uint8_t *)"\1",
+ sizeof(uint8_t), 1, f, stream,
+ stream_size, crc);
+ } else {
+ /* \todo check the return value */
+ fwrite_wrapper((uint8_t *)"\0", sizeof(uint8_t),
+ 1, f, stream, stream_size, crc);
+ }
+
+ if (use_ids && wildcard) {
+ /* \todo check the return value */
+ fwrite_wrapper((uint8_t *)"\1",
+ sizeof(uint8_t), 1, f, stream,
+ stream_size, crc);
+ uint32_t wildcard_id = wildcard->id;
+ /* \todo check the return value */
+ fwrite_wrapper(&wildcard_id,
+ sizeof(wildcard_id), 1, f, stream,
+ stream_size, crc);
+ } else {
+ /* \todo check the return value */
+ fwrite_wrapper((uint8_t *)"\0", sizeof(uint8_t),
+ 1, f, stream,
+ stream_size, crc);
+ }
+
+ } else {
+ dbg_zdump("Writing raw data. Item nr.: %d\n",
+ i);
+ assert(rdata->items[i].raw_data != NULL);
+ /* \todo check the return value */
+ fwrite_wrapper(rdata->items[i].raw_data,
+ sizeof(uint8_t),
+ rdata->items[i].raw_data[0] + 2, f,
+ stream, stream_size, crc);
+
+ dbg_zdump("Written %d long raw data\n",
+ rdata->items[i].raw_data[0]);
+ }
+ }
+}
+
+/*!
+ * \brief Dumps RRSIG in binary format to given file.
+ *
+ * \param rrsig RRSIG to be dumped.
+ * \param data Arguments to be propagated.
+ */
+static void knot_rrsig_set_dump_binary(knot_rrset_t *rrsig, arg_t *data,
+ int use_ids,
+ uint8_t **stream, size_t *stream_size,
+ crc_t *crc)
+{
+ dbg_zdump("Dumping rrset \\w owner: %s\n",
+ knot_dname_to_str(rrsig->owner));
+ assert(rrsig->type == KNOT_RRTYPE_RRSIG);
+ assert(rrsig->rdata);
+ FILE *f = (FILE *)((arg_t *)data)->arg1;
+ /* \todo check the return value */
+ fwrite_wrapper(&rrsig->type, sizeof(rrsig->type), 1, f,
+ stream, stream_size, crc);
+ fwrite_wrapper(&rrsig->rclass, sizeof(rrsig->rclass), 1, f,
+ stream, stream_size, crc);
+ fwrite_wrapper(&rrsig->ttl, sizeof(rrsig->ttl), 1, f,
+ stream, stream_size, crc);
+
+ uint32_t rdata_count = 1;
+ /* Calculate rrset rdata count. */
+ knot_rdata_t *tmp_rdata = rrsig->rdata;
+ while(tmp_rdata->next != rrsig->rdata) {
+ tmp_rdata = tmp_rdata->next;
+ rdata_count++;
+ }
+
+ fwrite_wrapper(&rdata_count, sizeof(rdata_count), 1, f,
+ stream, stream_size, crc);
+
+ tmp_rdata = rrsig->rdata;
+ while (tmp_rdata->next != rrsig->rdata) {
+ knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, data,
+ use_ids, stream, stream_size, crc);
+ tmp_rdata = tmp_rdata->next;
+ }
+ knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, data, use_ids,
+ stream, stream_size, crc);
+}
+
+/*!
+ * \brief Dumps RRSet in binary format to given file.
+ *
+ * \param rrset RRSSet to be dumped.
+ * \param data Arguments to be propagated.
+ */
+static void knot_rrset_dump_binary(const knot_rrset_t *rrset, void *data,
+ int use_ids,
+ uint8_t **stream, size_t *stream_size,
+ crc_t *crc)
+{
+ FILE *f = (FILE *)((arg_t *)data)->arg1;
+
+ if (!use_ids) {
+ dump_dname_with_id(rrset->owner, f, stream, stream_size, crc);
+ }
+
+ /* \todo check the return value */
+ fwrite_wrapper(&rrset->type, sizeof(rrset->type), 1, f,
+ stream, stream_size, crc);
+ fwrite_wrapper(&rrset->rclass, sizeof(rrset->rclass), 1, f,
+ stream, stream_size, crc);
+ fwrite_wrapper(&rrset->ttl, sizeof(rrset->ttl), 1, f,
+ stream, stream_size, crc);
+
+ uint32_t rdata_count = 1;
+ uint8_t has_rrsig = rrset->rrsigs != NULL;
+
+ /* Calculate rrset rdata count. */
+ knot_rdata_t *tmp_rdata = rrset->rdata;
+ while(tmp_rdata->next != rrset->rdata) {
+ tmp_rdata = tmp_rdata->next;
+ rdata_count++;
+ }
+
+ fwrite_wrapper(&rdata_count, sizeof(rdata_count), 1, f,
+ stream, stream_size, crc);
+ fwrite_wrapper(&has_rrsig, sizeof(has_rrsig), 1, f,
+ stream, stream_size, crc);
+
+ tmp_rdata = rrset->rdata;
+
+ while (tmp_rdata->next != rrset->rdata) {
+ knot_rdata_dump_binary(tmp_rdata, rrset->type, data, use_ids,
+ stream, stream_size, crc);
+ tmp_rdata = tmp_rdata->next;
+ }
+ knot_rdata_dump_binary(tmp_rdata, rrset->type, data, use_ids,
+ stream, stream_size, crc);
+
+ /* This is now obsolete, although I'd rather not use recursion - that
+ * would probably not work */
+
+ if (rrset->rrsigs != NULL) {
+ knot_rrsig_set_dump_binary(rrset->rrsigs, data, use_ids,
+ stream, stream_size, crc);
+ }
+}
+
+/*!
+ * \brief Dumps all RRSets in node to file in binary format.
+ *
+ * \param node Node to dumped.
+ * \param data Arguments to be propagated.
+ */
+static void knot_node_dump_binary(knot_node_t *node, void *data,
+ uint8_t **stream, size_t *stream_size,
+ crc_t *crc)
+{
+ arg_t *args = (arg_t *)data;
+ FILE *f = (FILE *)args->arg1;
+
+// node_count++;
+ /* first write dname */
+ assert(node->owner != NULL);
+
+ /* Write owner ID. */
+ dbg_zdump("Dumping node owned by %s\n",
+ knot_dname_to_str(node->owner));
+ assert(node->owner->id != 0);
+ uint32_t owner_id = node->owner->id;
+ /* \todo check the return value */
+ fwrite_wrapper(&owner_id, sizeof(owner_id), 1, f, stream, stream_size,
+ crc);
+
+ if (knot_node_parent(node, 0) != NULL) {
+ uint32_t parent_id = knot_dname_id(
+ knot_node_owner(knot_node_parent(node, 0)));
+ fwrite_wrapper(&parent_id, sizeof(parent_id), 1, f,
+ stream, stream_size, crc);
+ } else {
+ uint32_t parent_id = 0;
+ fwrite_wrapper(&parent_id, sizeof(parent_id), 1, f,
+ stream, stream_size, crc);
+ }
+
+ fwrite_wrapper(&(node->flags), sizeof(node->flags), 1, f,
+ stream, stream_size, crc);
+
+ dbg_zdump("Written flags: %u\n", node->flags);
+
+ if (knot_node_nsec3_node(node, 0) != NULL) {
+ uint32_t nsec3_id =
+ knot_node_owner(knot_node_nsec3_node(node, 0))->id;
+ fwrite_wrapper(&nsec3_id, sizeof(nsec3_id), 1, f,
+ stream, stream_size, crc);
+ dbg_zdump("Written nsec3 node id: %u\n",
+ knot_node_owner(knot_node_nsec3_node(node, 0))->id);
+ } else {
+ uint32_t nsec3_id = 0;
+ fwrite_wrapper(&nsec3_id, sizeof(nsec3_id), 1, f,
+ stream, stream_size, crc);
+ }
+
+ /* Now we need (or do we?) count of rrsets to be read
+ * but that number is yet unknown */
+
+ uint16_t rrset_count = node->rrset_count;
+ fwrite_wrapper(&rrset_count, sizeof(rrset_count), 1, f,
+ stream, stream_size, crc);
+
+ /* CLEANUP */
+// const skip_node_t *skip_node = skip_first(node->rrsets);
+
+ const knot_rrset_t **node_rrsets = knot_node_rrsets(node);
+ for (int i = 0; i < rrset_count; i++)
+ {
+ knot_rrset_dump_binary(node_rrsets[i], data, 1,
+ stream, stream_size, crc);
+ }
+
+ /* CLEANUP */
+// if (skip_node == NULL) {
+// /* we can return, count is set to 0 */
+// return;
+// }
+
+// knot_rrset_t *tmp;
+
+// do {
+// tmp = (knot_rrset_t *)skip_node->value;
+// knot_rrset_dump_binary(tmp, data, 1);
+// } while ((skip_node = skip_next(skip_node)) != NULL);
+
+ free(node_rrsets);
+
+ dbg_zdump("Position after all rrsets: %ld\n", ftell(f));
+ dbg_zdump("Writing here: %ld\n", ftell(f));
+ dbg_zdump("Function ends with: %ld\n\n", ftell(f));
+}
+
+/*!
+ * \brief Checks if zone uses DNSSEC and/or NSEC3
+ *
+ * \param zone Zone to be checked.
+ *
+ * \retval 0 if zone is not secured.
+ * \retval 2 if zone uses NSEC3
+ * \retval 1 if zone uses NSEC
+ */
+static int zone_is_secure(knot_zone_contents_t *zone)
+{
+ if (knot_node_rrset(knot_zone_contents_apex(zone),
+ KNOT_RRTYPE_DNSKEY) == NULL) {
+ return 0;
+ } else {
+ if (knot_node_rrset(knot_zone_contents_apex(zone),
+ KNOT_RRTYPE_NSEC3PARAM) != NULL) {
+ return 2;
+ } else {
+ return 1;
+ }
+ }
+}
+
+/*!
+ * \brief Checks if last node in NSEC/NSEC3 chain points to first node in the
+ * chain and prints possible errors.
+ *
+ * \param handler Semantic error handler.
+ * \param zone Current zone.
+ * \param last_node Last node in NSEC/NSEC3 chain.
+ * \param do_checks Level of semantic checks.
+ */
+static void log_cyclic_errors_in_zone(err_handler_t *handler,
+ knot_zone_contents_t *zone,
+ knot_node_t *last_node,
+ const knot_node_t *first_nsec3_node,
+ const knot_node_t *last_nsec3_node,
+ char do_checks)
+{
+ if (do_checks == 3) {
+ /* Each NSEC3 node should only contain one RRSET. */
+ assert(last_nsec3_node && first_nsec3_node);
+ const knot_rrset_t *nsec3_rrset =
+ knot_node_rrset(last_nsec3_node,
+ KNOT_RRTYPE_NSEC3);
+ if (nsec3_rrset == NULL) {
+ err_handler_handle_error(handler, last_nsec3_node,
+ ZC_ERR_NSEC3_RDATA_CHAIN);
+ return;
+ }
+
+ /* check that next dname is in the zone */
+ uint8_t *next_dname_decoded = NULL;
+ size_t real_size = 0;
+
+ if (((real_size = base32hex_encode_alloc(((char *)
+ rdata_item_data(&(nsec3_rrset->rdata->items[4]))) + 1,
+ rdata_item_size(&nsec3_rrset->rdata->items[4]) - 1,
+ (char **)&next_dname_decoded)) <= 0) ||
+ (next_dname_decoded == NULL)) {
+ fprintf(stderr, "Could not encode base32 string!\n");
+ err_handler_handle_error(handler, last_nsec3_node,
+ ZC_ERR_NSEC3_RDATA_CHAIN);
+ return;
+ }
+
+ /* This is why allocate maximum length of decoded string + 1 */
+ memmove(next_dname_decoded + 1, next_dname_decoded, real_size);
+ next_dname_decoded[0] = real_size;
+
+ /* Local allocation, will be discarded. */
+ knot_dname_t *next_dname =
+ knot_dname_new_from_wire(next_dname_decoded,
+ real_size + 1, NULL);
+ if (next_dname == NULL) {
+ fprintf(stderr, "Could not allocate dname!\n");
+ err_handler_handle_error(handler, last_nsec3_node,
+ ZC_ERR_ALLOC);
+ return;
+ }
+
+ free(next_dname_decoded);
+
+ /*! \todo Free result and dname! */
+ if (knot_dname_cat(next_dname,
+ knot_node_owner(knot_zone_contents_apex(zone))) ==
+ NULL) {
+ fprintf(stderr, "Could not concatenate dnames!\n");
+ err_handler_handle_error(handler, last_nsec3_node,
+ ZC_ERR_NSEC3_RDATA_CHAIN);
+ return;
+ }
+
+ /* Check it points somewhere first. */
+ if (knot_zone_contents_find_nsec3_node(zone, next_dname) == NULL) {
+ err_handler_handle_error(handler, last_nsec3_node,
+ ZC_ERR_NSEC3_RDATA_CHAIN);
+ }
+
+ /* Compare with the actual first NSEC3 node. */
+ if (knot_dname_compare(first_nsec3_node->owner,
+ next_dname) != 0) {
+ err_handler_handle_error(handler, last_nsec3_node,
+ ZC_ERR_NSEC3_RDATA_CHAIN);
+ }
+
+ /* Directly discard. */
+ knot_dname_free(&next_dname);
+
+ } else if (do_checks == 2 ) {
+ if (last_node == NULL) {
+ err_handler_handle_error(handler, last_node,
+ ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC);
+ return;
+ } else {
+ const knot_rrset_t *nsec_rrset =
+ knot_node_rrset(last_node,
+ KNOT_RRTYPE_NSEC);
+
+ if (nsec_rrset == NULL) {
+ err_handler_handle_error(handler, last_node,
+ ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC);
+ return;
+ }
+
+ const knot_dname_t *next_dname =
+ knot_rdata_item(
+ knot_rrset_rdata(nsec_rrset), 0)->dname;
+ assert(next_dname);
+
+ const knot_dname_t *apex_dname =
+ knot_node_owner(knot_zone_contents_apex(zone));
+ assert(apex_dname);
+
+ if (knot_dname_compare(next_dname, apex_dname) !=0) {
+ err_handler_handle_error(handler, last_node,
+ ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC);
+ }
+ }
+ }
+}
+
+/*!
+ * \brief Safe wrapper around fwrite.
+ *
+ * \param dst Destination pointer.
+ * \param size Size of element to be written.
+ * \param n Number of elements to be written.
+ * \param fp File to write to.
+ *
+ * \retval > 0 if succesfull.
+ * \retval 0 if failed.
+ */
+//static inline int fwrite_wrapper_safe(const void *src,
+// size_t size, size_t n, FILE *fp)
+//{
+// int rc = fwrite_wrapper(src, size, n, fp);
+// if (rc != n) {
+// fprintf(stderr, "fwrite_wrapper: invalid write %d (expected %zu)\n", rc,
+// n);
+// }
+
+// return rc == n;
+//}
+
+static void dump_dname_from_tree(knot_dname_t *dname,
+ void *data)
+{
+ arg_t *arg = (arg_t *)data;
+ FILE *f = (FILE *)arg->arg1;
+ crc_t *crc = (crc_t*)arg->arg2;
+ dump_dname_with_id(dname, f, NULL, NULL, crc);
+}
+
+static int knot_dump_dname_table(const knot_dname_table_t *dname_table,
+ FILE *f, crc_t *crc)
+{
+ arg_t arg;
+ arg.arg1 = f;
+ arg.arg2 = crc;
+ /* Go through the tree and dump each dname along with its ID. */
+ knot_dname_table_tree_inorder_apply(dname_table,
+ dump_dname_from_tree, &arg);
+ /* CLEANUP */
+// TREE_FORWARD_APPLY(dname_table->tree, dname_table_node, avl,
+// dump_dname_from_tree, (void *)f);
+
+ return KNOT_EOK;
+}
+
+static void save_node_from_tree(knot_node_t *node, void *data)
+{
+ arg_t *arg = (arg_t *)data;
+ /* Increment node count */
+ (*((uint32_t *)(arg->arg1)))++;
+ /* Save the first node only */
+ if (arg->arg2 == NULL) {
+ arg->arg2 = (void *)node;
+ }
+ arg->arg3 = (void *)node;
+}
+
+static void dump_node_to_file(knot_node_t *node, void *data)
+{
+ arg_t *arg = (arg_t *)data;
+ knot_node_dump_binary(node, data, NULL, NULL, (crc_t *)arg->arg7);
+}
+
+int knot_zdump_binary(knot_zone_contents_t *zone, const char *filename,
+ int do_checks, const char *sfilename)
+{
+ /* Open .new file. */
+ char new_path[strlen(filename) + strlen(".new") + 1];
+ memcpy(new_path, filename, strlen(filename) + 1);
+ strcat(new_path, ".new");
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ int fd = open(new_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ if (fd == -1) {
+ return KNOT_EBADARG;
+ }
+
+ FILE *f = fdopen(fd, "wb");
+ assert(f);
+
+ /* CLEANUP */
+// skip_list_t *encloser_list = skip_create_list(compare_pointers);
+ arg_t arguments;
+ /* Memory to be derefenced in the save_node_from_tree function. */
+ uint32_t node_count = 0;
+ arguments.arg1 = &node_count;
+ arguments.arg2 = NULL;
+
+ /* Count number of normal nodes. */
+ knot_zone_contents_tree_apply_inorder(zone, save_node_from_tree, &arguments);
+ /* arg1 is now count of normal nodes */
+ uint32_t normal_node_count = *((uint32_t *)arguments.arg1);
+
+ node_count = 0;
+ arguments.arg1 = &node_count;
+ arguments.arg2 = NULL;
+
+ /* Count number of NSEC3 nodes. */
+ knot_zone_contents_nsec3_apply_inorder(zone, save_node_from_tree, &arguments);
+ uint32_t nsec3_node_count = *((uint32_t *)arguments.arg1);
+ /* arg2 is the first NSEC3 node - used in sem checks. */
+ /* arg3 is the last NSEC3 node - used in sem checks. */
+ const knot_node_t *first_nsec3_node = (knot_node_t *)arguments.arg2;
+ const knot_node_t *last_nsec3_node = (knot_node_t *)arguments.arg3;
+
+ if (do_checks && zone_is_secure(zone)) {
+ do_checks += zone_is_secure(zone);
+ }
+
+ err_handler_t *handler = NULL;
+
+ if (do_checks) {
+ handler = handler_new(1, 0, 1, 1, 1);
+ if (handler == NULL) {
+ /* disable checks and we can continue */
+ do_checks = 0;
+ } else { /* Do check for SOA right now */
+ if (knot_node_rrset(knot_zone_contents_apex(zone),
+ KNOT_RRTYPE_SOA) == NULL) {
+ err_handler_handle_error(handler,
+ knot_zone_contents_apex(zone),
+ ZC_ERR_MISSING_SOA);
+ }
+ }
+
+ knot_node_t *last_node = NULL;
+
+ zone_do_sem_checks(zone, do_checks, handler, &last_node);
+ log_cyclic_errors_in_zone(handler, zone, last_node,
+ first_nsec3_node, last_nsec3_node,
+ do_checks);
+ err_handler_log_all(handler);
+ free(handler);
+ }
+
+ crc_t crc = crc_init();
+
+ /* Start writing header - magic bytes. */
+ static const uint8_t MAGIC[MAGIC_LENGTH] = MAGIC_BYTES;
+ fwrite_wrapper(&MAGIC, sizeof(uint8_t), MAGIC_LENGTH, f, NULL, NULL,
+ &crc);
+
+ /* Write source file length. */
+ uint32_t sflen = 0;
+ if (sfilename) {
+ sflen = strlen(sfilename) + 1;
+ }
+ fwrite_wrapper(&sflen, sizeof(uint32_t), 1, f, NULL, NULL, &crc);
+
+ /* Write source file. */
+ fwrite_wrapper(sfilename, sflen, 1, f, NULL, NULL, &crc);
+
+ /* Notice: End of header,
+ */
+
+ /* Start writing compiled data. */
+ fwrite_wrapper(&normal_node_count, sizeof(normal_node_count), 1, f,
+ NULL, NULL, &crc);
+ fwrite_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, f,
+ NULL, NULL, &crc);
+ uint32_t auth_node_count = zone->node_count;
+ fwrite_wrapper(&auth_node_count,
+ sizeof(auth_node_count), 1, f, NULL, NULL, &crc);
+
+ /* Write total number of dnames */
+ assert(zone->dname_table);
+ uint32_t total_dnames = zone->dname_table->id_counter;
+ fwrite_wrapper(&total_dnames,
+ sizeof(total_dnames), 1, f, NULL, NULL, &crc);
+
+ /* Write dname table. */
+ if (knot_dump_dname_table(zone->dname_table, f, &crc)
+ != KNOT_EOK) {
+ return KNOT_ERROR;
+ }
+
+ arguments.arg1 = (void *)f;
+ arguments.arg3 = zone;
+ arguments.arg7 = &crc;
+
+ /* TODO is there a way how to stop the traversal upon error? */
+ knot_zone_contents_tree_apply_inorder(zone, dump_node_to_file,
+ (void *)&arguments);
+
+ knot_zone_contents_nsec3_apply_inorder(zone, dump_node_to_file,
+ (void *)&arguments);
+ fclose(f);
+
+ crc = crc_finalize(crc);
+ /* Write CRC to separate .crc file. */
+ /*!< \todo There is now function doing this. */
+ char *crc_path =
+ malloc(sizeof(char) * (strlen(filename) + strlen(".crc") + 1));
+ if (unlikely(!crc_path)) {
+ close(fd);
+ return KNOT_ENOMEM;
+ }
+ memset(crc_path, 0,
+ sizeof(char) * (strlen(filename) + strlen(".crc") + 1));
+ memcpy(crc_path, filename, sizeof(char) * strlen(filename));
+
+ crc_path = strcat(crc_path, ".crc");
+ FILE *f_crc = fopen(crc_path, "w");
+ if (unlikely(!f_crc)) {
+ dbg_zload("knot_zload_open: failed to open '%s'\n",
+ crc_path);
+ close(fd);
+ free(crc_path);
+ return ENOENT;
+ }
+ free(crc_path);
+
+ fprintf(f_crc, "%lu\n", (unsigned long)crc);
+ fclose(f_crc);
+
+ close(fd);
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ fd = open(filename, O_WRONLY | O_CREAT, mode);
+ if (fd == -1) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ fprintf(stderr, "Could not open destination file! Use '%s' "
+ "file instead.\n", new_path);
+ return KNOT_ERROR;
+ }
+
+ /* Try to obtain exclusive lock for originally given file. */
+ if (fcntl(fd, F_SETLK, knot_file_lock(F_WRLCK, SEEK_SET)) == -1) {
+ fprintf(stderr, "Could not lock destination file for write! "
+ "Use '%s' file instead.\n", new_path);
+ close(fd);
+ return KNOT_ERROR;
+ }
+
+ /* Move .new file to original file. */
+ if (rename(new_path, filename) != 0) {
+ fprintf(stderr, "Could not move to originally given file! "
+ "Use '%s' file instead.\n", new_path);
+ close(fd);
+ return KNOT_ERROR;
+ }
+
+ /* Release the lock. */
+ if (fcntl(fd, F_SETLK, knot_file_lock(F_UNLCK, SEEK_SET)) == -1) {
+ fprintf(stderr, "Could not unlock destination file!\n");
+ return KNOT_ERROR;
+ }
+
+ close(fd);
+
+ return KNOT_EOK;
+}
+
+int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream,
+ size_t *size)
+{
+ if (stream == NULL || *stream != NULL || rrset == NULL ||
+ size == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ *size = 0;
+ arg_t arguments;
+ memset(&arguments, 0, sizeof(arg_t));
+
+ knot_rrset_dump_binary(rrset, &arguments, 0, stream, size, NULL);
+
+ return KNOT_EOK;
+}
+
+static char *knot_zdump_crc_file(const char* filename)
+{
+ char *crc_path =
+ malloc(sizeof(char) * (strlen(filename) +
+ strlen(".crc") + 1));
+ CHECK_ALLOC_LOG(crc_path, NULL);
+ memset(crc_path, 0,
+ sizeof(char) * (strlen(filename) +
+ strlen(".crc") + 1));
+ memcpy(crc_path, filename,
+ sizeof(char) * strlen(filename));
+ crc_path = strcat(crc_path, ".crc");
+ return crc_path;
+}
+
+int knot_zdump_dump_and_swap(knot_zone_contents_t *zone,
+ const char *temp_zonedb,
+ const char *destination_zonedb,
+ const char *sfilename)
+{
+ int rc = knot_zdump_binary(zone, temp_zonedb, 0, sfilename);
+
+ if (rc != KNOT_EOK) {
+ dbg_zdump("Failed to save the zone to binary zone db %s."
+ "\n", temp_zonedb);
+ return KNOT_ERROR;
+ }
+
+ /*! \todo this would also need locking as well. */
+ rc = remove(destination_zonedb);
+ if (rc == 0 || (rc != 0 && errno == ENOENT)) {
+
+ /* Delete old CRC file. */
+ char *destination_zonedb_crc =
+ knot_zdump_crc_file(destination_zonedb);
+ if (destination_zonedb_crc == NULL) {
+ return KNOT_ENOMEM;
+ }
+ remove(destination_zonedb_crc);
+
+ /* Move CRC file. */
+ char *temp_zonedb_crc =
+ knot_zdump_crc_file(temp_zonedb);
+ if (temp_zonedb_crc == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ if (rename(temp_zonedb_crc, destination_zonedb_crc) != 0) {
+ dbg_zdump("Failed to replace old zonedb CRC %s "
+ "with new CRC zone file %s.\n",
+ destination_zonedb_crc,
+ temp_zonedb_crc);
+ return KNOT_ERROR;
+ }
+ free(temp_zonedb_crc);
+ free(destination_zonedb_crc);
+
+ /* Rename zonedb. */
+ if (rename(temp_zonedb, destination_zonedb) != 0) {
+ dbg_zdump("Failed to replace old zonedb %s "
+ "with new zone file %s.\n",
+ temp_zonedb,
+ destination_zonedb);
+ /*! \todo with proper locking, this shouldn't happen,
+ * revise it later on.
+ */
+ return KNOT_ERROR;
+ }
+ } else {
+ dbg_zdump("Failed to replace old zonedb '%s'', %s.\n",
+ destination_zonedb, strerror(errno));
+ return KNOT_ERROR;
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/knot/zone/zone-dump.h b/src/knot/zone/zone-dump.h
new file mode 100644
index 0000000..daf6c18
--- /dev/null
+++ b/src/knot/zone/zone-dump.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file zone-dump.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief Functions for dumping zone to binary file.
+ *
+ * \addtogroup dnslib
+ * @{
+ */
+
+#ifndef _KNOT_ZONEDUMP_H_
+#define _KNOT_ZONEDUMP_H_
+
+#include "common/crc.h"
+#include "libknot/zone/zone.h"
+
+/*!
+ * \brief Zone loader enums.
+ */
+enum {
+ MAGIC_LENGTH = 7 /*!< Compiled zone magic length. */
+};
+
+/*! \brief Magic identifier: { "knot", maj_ver, min_ver, revision } */
+#define MAGIC_BYTES {'k', 'n', 'o', 't', '0', '8', '0'}
+
+/*!
+ * \brief Dumps given zone to binary file.
+ *
+ * \param zone Zone to be saved.
+ * \param filename Name of file to be created.
+ * \param do_checks Set to 1 to enable checking the zone for semantic errors.
+ * \param sfilename Source filename of the text zone file.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EBADARG if the file cannot be opened for writing.
+ */
+int knot_zdump_binary(knot_zone_contents_t *zone, const char *filename,
+ int do_checks, const char *sfilename);
+
+/*!
+ * \brief Serializes RRSet into binary stream. Expects NULL pointer, memory
+ * is handled inside function.
+ *
+ * \param rrset RRSet to be serialized.
+ * \param stream Stream containing serialized RRSet.
+ * \param size Length of created stream.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EBADARG if wrong arguments are supplied.
+ * \retval KNOT_ENOMEM on memory error.
+ */
+int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream,
+ size_t *size);
+
+/*!
+ * \brief Serializes RRSet into binary stream. Expects NULL pointer, memory
+ * is handled inside function.
+ *
+ * \param rrset RRSet to be serialized.
+ * \param stream Stream containing serialized RRSet.
+ * \param size Length of created stream.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EBADARG if wrong arguments are supplied.
+ * \retval KNOT_ENOMEM on memory error.
+ */
+int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream,
+ size_t *size);
+
+int knot_zdump_dump_and_swap(knot_zone_contents_t *zone,
+ const char *temp_zonedb,
+ const char *destination_zonedb,
+ const char *sfilename);
+
+#endif /* _KNOT_ZONEDUMP_H_ */
+
+/*! @} */
diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c
new file mode 100644
index 0000000..9ab0e8d
--- /dev/null
+++ b/src/knot/zone/zone-load.c
@@ -0,0 +1,1209 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "common/crc.h"
+#include "libknot/common.h"
+#include "knot/other/debug.h"
+#include "knot/zone/zone-load.h"
+#include "knot/zone/zone-dump.h"
+#include "libknot/libknot.h"
+
+/*!
+ * \brief Compares two time_t values.
+ *
+ * \param x First time_t value to be compared.
+ * \param y Second time_t value to be compared.
+ *
+ * \retval 0 when times are the some.
+ * \retval 1 when y < x.
+ * \retval -1 when x > y.
+ */
+static int timet_cmp(time_t x, time_t y)
+{
+ /* Calculate difference in the scale of seconds. */
+ long diff = x - y;
+
+ /* X and Y are equal. */
+ if (diff == 0) {
+ return 0;
+ }
+
+ /* X is newer. */
+ if (diff > 0) {
+ return 1;
+ }
+
+ /* Y is newer. */
+ return -1;
+}
+
+/*!
+ * \brief Safe wrapper around fread.
+ *
+ * \param dst Destination pointer.
+ * \param size Size of element to be read.
+ * \param n Number of elements to be read.
+ * \param fp File to read from.
+ *
+ * \retval > 0 if succesfull.
+ * \retval 0 if failed.
+ */
+static inline int fread_safe_from_file(void *dst,
+ size_t size, size_t n, FILE *fp)
+{
+ int rc = fread(dst, size, n, fp);
+ if (rc != n) {
+ fprintf(stderr, "fread: invalid read %d (expected %zu)\n", rc,
+ n);
+ }
+
+ return rc == n;
+}
+
+static uint8_t *knot_zload_stream = NULL;
+static size_t knot_zload_stream_remaining = 0;
+static size_t knot_zload_stream_size = 0;
+
+static inline int read_from_stream(void *dst,
+ size_t size, size_t n, FILE *fp)
+{
+ if (knot_zload_stream_remaining < (size * n)) {
+ return 0;
+ }
+
+ memcpy(dst,
+ knot_zload_stream +
+ (knot_zload_stream_size - knot_zload_stream_remaining),
+ size * n);
+ knot_zload_stream_remaining -= size * n;
+
+ return 1;
+}
+
+static int (*fread_wrapper)(void *dst, size_t size, size_t n, FILE *fp);
+
+/*! \note Contents of dump file:
+ * MAGIC(knotxx) NUMBER_OF_NORMAL_NODES NUMBER_OF_NSEC3_NODES
+ * [normal_nodes] [nsec3_nodes]
+ * node has following format:
+ * owner_size owner_wire owner_label_size owner_labels owner_id
+ * node_flags node_rrset_count [node_rrsets]
+ * rrset has following format:
+ * rrset_type rrset_class rrset_ttl rrset_rdata_count rrset_rrsig_count
+ * [rrset_rdata] [rrset_rrsigs]
+ * rdata can either contain full dnames (that is with labels but without ID)
+ * or dname ID, if dname is in the zone
+ * or raw data stored like this: data_len [data]
+ */
+
+enum { DNAME_MAX_WIRE_LENGTH = 256 };
+
+/*!
+ * \brief Helper function. Frees rdata items and temporary array of items.
+ *
+ * \param rdata Rdata to be freed.
+ * \param items Items to be freed.
+ * \param count Current count of rdata items.
+ * \param type RRSet type.
+ */
+static void load_rdata_purge(knot_rdata_t *rdata,
+ knot_rdata_item_t *items,
+ int count,
+ knot_rrtype_descriptor_t *desc,
+ uint16_t type)
+{
+ /* Increase refcount manually, as the set_items() doesn't see the dname
+ * type and thus is unable to increment refcounter.
+ */
+ for (int i = 0; i < count; ++i) {
+ switch(desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ knot_dname_retain(items[i].dname);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Copy items to rdata and free the temporary rdata. */
+ knot_rdata_set_items(rdata, items, count);
+ knot_rdata_deep_free(&rdata, type, 1);
+ free(items);
+}
+
+static knot_dname_t *read_dname_with_id(FILE *f)
+{
+ knot_dname_t *ret = knot_dname_new();
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ /* Read ID. */
+ uint32_t dname_id = 0;
+ if (!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) {
+ knot_dname_release(ret);
+ return NULL;
+ }
+
+ ret->id = dname_id;
+ dbg_zload("loaded: dname id: %u\n", dname_id);
+
+ /* Read size of dname. */
+ uint32_t dname_size = 0;
+ if (!fread_wrapper(&dname_size, sizeof(dname_size), 1, f)) {
+ knot_dname_release(ret);
+ return NULL;
+ }
+ ret->size = dname_size;
+ dbg_zload("loaded: dname length: %u\n", ret->size);
+
+ assert(ret->size <= DNAME_MAX_WIRE_LENGTH);
+
+ /* Read wireformat of dname. */
+ ret->name = malloc(sizeof(uint8_t) * ret->size);
+ if (ret->name == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_dname_release(ret);
+ return NULL;
+ }
+
+ if (!fread_wrapper(ret->name, sizeof(uint8_t), ret->size, f)) {
+ knot_dname_release(ret);
+ return NULL;
+ }
+
+ /* Read labels. */
+ uint16_t label_count = 0;
+ if (!fread_wrapper(&label_count, sizeof(label_count), 1, f)) {
+ knot_dname_release(ret);
+ return NULL;
+ }
+
+ ret->label_count = label_count;
+
+ ret->labels = malloc(sizeof(uint8_t) * ret->label_count);
+ if (ret->labels == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_dname_release(ret);
+ return NULL;
+ }
+
+ if (!fread_wrapper(ret->labels, sizeof(uint8_t), ret->label_count, f)) {
+ free(ret->name);
+ free(ret);
+ return NULL;
+ }
+
+ dbg_zload("loaded: %s (id: %d)\n", knot_dname_to_str(ret),
+ ret->id);
+
+ return ret;
+}
+
+/*!
+ * \brief Load rdata in binary format from file.
+ *
+ * \param type Type of RRSet containing read rdata.
+ * \param f File to read binary data from.
+ *
+ * \return Pointer to read and created rdata on success, NULL otherwise.
+ */
+static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f,
+ knot_dname_t **id_array,
+ int use_ids)
+{
+ knot_rdata_t *rdata = knot_rdata_new();
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ assert(desc != NULL);
+
+
+ /* First, should read rdata count. */
+
+ uint32_t rdata_count = 0;
+
+ if(!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) {
+ return NULL;
+ }
+
+ knot_rdata_item_t *items =
+ malloc(sizeof(knot_rdata_item_t) * rdata_count);
+
+ if (desc->fixed_items) {
+ assert(desc->length == rdata_count);
+ }
+
+ uint16_t raw_data_length;
+
+ dbg_zload("Reading %d items\n", rdata_count);
+
+ dbg_zload("current type: %s\n", knot_rrtype_to_string(type));
+
+ for (int i = 0; i < rdata_count; i++) {
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) {
+
+ /* TODO maybe this does not need to be stored this big*/
+
+ uint32_t dname_id = 0;
+ uint8_t has_wildcard = 0;
+ uint8_t in_the_zone = 0;
+
+ if (use_ids) {
+ if(!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) {
+ load_rdata_purge(rdata, items, i, desc, type);
+ return NULL;
+ }
+
+ /* Store reference do dname. */
+ knot_dname_retain(id_array[dname_id]);
+ items[i].dname = id_array[dname_id];
+ } else {
+ items[i].dname = read_dname_with_id(f);
+ }
+
+ if(!fread_wrapper(&in_the_zone, sizeof(in_the_zone),
+ 1, f)) {
+ load_rdata_purge(rdata, items, i, desc, type);
+ return NULL;
+ }
+
+ if(!fread_wrapper(&has_wildcard, sizeof(uint8_t),
+ 1, f)) {
+ load_rdata_purge(rdata, items, i, desc, type);
+ return NULL;
+ }
+
+ if (use_ids && has_wildcard) {
+ if(!fread_wrapper(&dname_id, sizeof(dname_id),
+ 1, f)) {
+ load_rdata_purge(rdata, items,
+ i, desc, type);
+ return NULL;
+ }
+ items[i].dname->node =
+ id_array[dname_id]->node;
+ } else if (use_ids && !in_the_zone) { /* destroy the node */
+ if (id_array[dname_id]->node != NULL) {
+ knot_node_free(&id_array[dname_id]->
+ node, 0, 0);
+ }
+ /* Also sets node to NULL! */
+ }
+ assert(items[i].dname);
+ } else {
+ if (!fread_wrapper(&raw_data_length,
+ sizeof(raw_data_length), 1, f)) {
+ load_rdata_purge(rdata, items, i, desc, type);
+ return NULL;
+ }
+
+ items[i].raw_data =
+ malloc(sizeof(uint8_t) * (raw_data_length + 2));
+ items[i].raw_data[0] = raw_data_length;
+
+ if (!fread_wrapper(items[i].raw_data + 1, sizeof(uint8_t),
+ raw_data_length, f)) {
+ load_rdata_purge(rdata, items, i + 1, desc, type);
+ return NULL;
+ }
+ dbg_zload("read raw_data len %d\n", raw_data_length);
+ }
+ }
+
+ /* Each item has refcount already incremented for saving in rdata. */
+ if (knot_rdata_set_items(rdata, items, rdata_count) != 0) {
+ fprintf(stderr, "zoneload: Could not set items "
+ "when loading rdata.\n");
+ }
+
+ free(items);
+
+ dbg_zload("knot_load_rdata: all %d items read\n",
+ desc->length);
+
+ assert(rdata->count == rdata_count);
+
+ rdata->count = rdata_count;
+
+ return rdata;
+}
+
+/*!
+ * \brief Loads RRSIG from binary file.
+ *
+ * \param f File to read from.
+ *
+ * \return pointer to created and read RRSIG on success, NULL otherwise.
+ */
+static knot_rrset_t *knot_load_rrsig(FILE *f, knot_dname_t **id_array,
+ int use_ids)
+{
+ knot_rrset_t *rrsig;
+
+ uint16_t rrset_type;
+ uint16_t rrset_class;
+ uint32_t rrset_ttl;
+
+ uint32_t rdata_count;
+
+ if (!fread_wrapper(&rrset_type, sizeof(rrset_type), 1, f)) {
+ return NULL;
+ }
+
+ if (rrset_type != KNOT_RRTYPE_RRSIG) {
+ fprintf(stderr, "!! Error: rrsig has wrong type\n");
+ return NULL;
+ }
+ dbg_zload("rrset type: %d\n", rrset_type);
+ if (!fread_wrapper(&rrset_class, sizeof(rrset_class), 1, f)) {
+ return NULL;
+ }
+ dbg_zload("rrset class %d\n", rrset_class);
+
+ if (!fread_wrapper(&rrset_ttl, sizeof(rrset_ttl), 1, f)) {
+ return NULL;
+ }
+ dbg_zload("rrset ttl %d\n", rrset_ttl);
+
+ if (!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) {
+ return NULL;
+ }
+
+ rrsig = knot_rrset_new(NULL, rrset_type, rrset_class, rrset_ttl);
+
+ knot_rdata_t *tmp_rdata;
+
+ dbg_zload("loading %d rdata entries\n", rdata_count);
+
+ for (int i = 0; i < rdata_count; i++) {
+ tmp_rdata = knot_load_rdata(KNOT_RRTYPE_RRSIG, f,
+ id_array, use_ids);
+ if (tmp_rdata) {
+ knot_rrset_add_rdata(rrsig, tmp_rdata);
+ } else {
+ knot_rrset_deep_free(&rrsig, 0, 1, 1);
+ return NULL;
+ }
+ }
+
+ return rrsig;
+}
+
+/*!
+ * \brief Loads RRSet from binary file.
+ *
+ * \param f File to read from.
+ *
+ * \return pointer to created and read RRSet on success, NULL otherwise.
+ */
+static knot_rrset_t *knot_load_rrset(FILE *f, knot_dname_t **id_array,
+ int use_ids)
+{
+ knot_rrset_t *rrset = NULL;
+
+ uint16_t rrset_type = 0;
+ uint16_t rrset_class = 0;
+ uint32_t rrset_ttl = 0;
+
+ uint32_t rdata_count = 0;
+ uint8_t rrsig_count = 0;
+
+ knot_dname_t *owner = NULL;
+
+ if (!use_ids) {
+ dbg_zload("Loading owner of new RRSet from wire.\n");
+ owner = read_dname_with_id(f);
+ }
+
+ if (!fread_wrapper(&rrset_type, sizeof(rrset_type), 1, f)) {
+ return NULL;
+ }
+ dbg_zload("Zone load: rrset load: type: %u\n", rrset_type);
+ if (!fread_wrapper(&rrset_class, sizeof(rrset_class), 1, f)) {
+ return NULL;
+ }
+ dbg_zload("Zone load: rrset class: type: %u\n", rrset_class);
+ if (!fread_wrapper(&rrset_ttl, sizeof(rrset_ttl), 1, f)) {
+ return NULL;
+ }
+ dbg_zload("Zone load: rrset ttl: type: %u\n", rrset_ttl);
+ if (!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) {
+ return NULL;
+ }
+ dbg_zload("Zone load: rrset load: rdata count: %u\n", rdata_count);
+ if (!fread_wrapper(&rrsig_count, sizeof(rrsig_count), 1, f)) {
+ return NULL;
+ }
+ dbg_zload("Zone load: rrset load: type: %u\n", rrset_type);
+
+ dbg_zload("Loading RRSet owned by: %s\n",
+ knot_dname_to_str(owner));
+
+ rrset = knot_rrset_new(owner, rrset_type, rrset_class, rrset_ttl);
+
+ if (!use_ids) {
+ /* Directly release if allocated locally. */
+ knot_dname_release(owner);
+ owner = 0;
+ }
+
+ dbg_zload("RRSet type: %d\n", rrset->type);
+
+ knot_rdata_t *tmp_rdata = NULL;
+
+ for (int i = 0; i < rdata_count; i++) {
+ tmp_rdata = knot_load_rdata(rrset->type, f,
+ id_array, use_ids);
+ if (tmp_rdata) {
+ knot_rrset_add_rdata(rrset, tmp_rdata);
+ } else {
+ knot_rrset_deep_free(&rrset, 0, 1, 1);
+ return NULL;
+ }
+ }
+
+ knot_rrset_t *tmp_rrsig = NULL;
+
+ dbg_zload("Reading: %d RRSIGs\n", rrsig_count);
+ if (rrsig_count) {
+ tmp_rrsig = knot_load_rrsig(f, id_array, use_ids);
+ if (!use_ids) {
+ knot_rrset_set_owner(tmp_rrsig, rrset->owner);
+ }
+ }
+
+ knot_rrset_set_rrsigs(rrset, tmp_rrsig);
+
+ dbg_zload("Finished loading RRSet %p\n", rrset);
+
+ return rrset;
+}
+
+/*!
+ * \brief Loads node from binary file.
+ *
+ * \param f File to read from.
+ *
+ * \return Pointer to created and read node on success, NULL otherwise.
+ */
+static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array)
+{
+ uint8_t flags = 0;
+ knot_node_t *node = NULL;
+ uint32_t parent_id = 0;
+ uint32_t nsec3_node_id = 0;
+ uint16_t rrset_count = 0;
+ uint32_t dname_id = 0;
+
+ /* At the beginning of node - just dname_id !!!.*/
+ if (!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) {
+ return NULL;
+ }
+
+ if (!fread_wrapper(&parent_id, sizeof(parent_id), 1, f)) {
+ return NULL;
+ }
+
+ if (!fread_wrapper(&flags, sizeof(flags), 1, f)) {
+ return NULL;
+ }
+
+ if (!fread_wrapper(&nsec3_node_id, sizeof(nsec3_node_id), 1, f)) {
+ return NULL;
+ }
+
+ if (!fread_wrapper(&rrset_count, sizeof(rrset_count), 1, f)) {
+ return NULL;
+ }
+ knot_dname_t *owner = id_array[dname_id];
+
+ dbg_zload("Node owner id: %d\n", dname_id);
+ dbg_zload("Node owned by: %s\n", knot_dname_to_str(owner));
+ dbg_zload("Number of RRSets in a node: %d\n", rrset_count);
+
+ node = owner->node;
+
+ if (node == NULL) {
+ fprintf(stderr, "zone: Could not create node.\n");
+ return NULL;
+ }
+ /* XXX can it be 0, ever? I think not. */
+ if (nsec3_node_id != 0) {
+ knot_node_set_nsec3_node(node, id_array[nsec3_node_id]->node);
+ /* CLEANUP */
+// node->nsec3_node = id_array[nsec3_node_id]->node;
+ } else {
+ knot_node_set_nsec3_node(node, NULL);
+ /* CLEANUP */
+// node->nsec3_node = NULL;
+ }
+
+ /* Retain new owner while releasing replaced owner. */
+ knot_node_set_owner(node, owner);
+ node->flags = flags;
+
+ //XXX will have to be set already...canonical order should do it
+
+ if (parent_id != 0) {
+ knot_node_set_parent(node, id_array[parent_id]->node);
+ assert(knot_node_parent(node, 0) != NULL);
+ } else {
+ knot_node_set_parent(node, NULL);
+ }
+
+ knot_rrset_t *tmp_rrset;
+
+ for (int i = 0; i < rrset_count; i++) {
+ if ((tmp_rrset = knot_load_rrset(f, id_array, 1)) == NULL) {
+ knot_node_free(&node, 1, 0);
+ //TODO what else to free?
+ fprintf(stderr, "zone: Could not load rrset.\n");
+ return NULL;
+ }
+ /* Retain new owner while releasing replaced owner. */
+ knot_rrset_set_owner(tmp_rrset, node->owner);
+ if (tmp_rrset->rrsigs != NULL) {
+ knot_rrset_set_owner(tmp_rrset->rrsigs, node->owner);
+ }
+ if (knot_node_add_rrset(node, tmp_rrset, 0) < 0) {
+ fprintf(stderr, "zone: Could not add rrset.\n");
+ return NULL;
+ }
+ }
+ assert(node != NULL);
+ dbg_zload("Node loaded: %p\n", node);
+ return node;
+}
+
+/*!
+ * \brief Finds and sets wildcard child for given node's owner.
+ *
+ * \param zone Current zone.
+ * \param node Node to be used.
+ * \param nsec3 Is NSEC3 node.
+ */
+static void find_and_set_wildcard_child(knot_zone_contents_t *zone,
+ knot_node_t *node, int nsec3)
+{
+ knot_dname_t *chopped = knot_dname_left_chop(node->owner);
+ assert(chopped);
+ knot_node_t *wildcard_parent;
+ if (!nsec3) {
+ wildcard_parent =
+ knot_zone_contents_get_node(zone, chopped);
+ } else {
+ wildcard_parent =
+ knot_zone_contents_get_nsec3_node(zone, chopped);
+ }
+
+ /* Directly discard. */
+ knot_dname_free(&chopped);
+
+ assert(wildcard_parent); /* it *has* to be there */
+
+ knot_node_set_wildcard_child(wildcard_parent, node);
+}
+
+/*!
+ * \brief Checks if magic string at the beginning of the file is the same
+ * as defined.
+ *
+ * \param f File to read magic string from.
+ * \param MAGIC Magic string.
+ * \param MAGIC_LENGTH Length of magic string.
+ *
+ * \retval 1 if magic is the same.
+ * \retval 0 otherwise.
+ */
+static int knot_check_magic(FILE *f, const uint8_t* MAGIC, uint MAGIC_LENGTH)
+{
+ uint8_t tmp_magic[MAGIC_LENGTH];
+
+ if (!fread_wrapper(&tmp_magic, sizeof(uint8_t), MAGIC_LENGTH, f)) {
+ return 0;
+ }
+
+ for (int i = 0; i < MAGIC_LENGTH; i++) {
+ if (tmp_magic[i] != MAGIC[i]) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static unsigned long calculate_crc(FILE *f)
+{
+ crc_t crc = crc_init();
+ /* Get file size. */
+ fseek(f, 0L, SEEK_END);
+ size_t file_size = ftell(f);
+ fseek(f, 0L, SEEK_SET);
+
+ const size_t chunk_size = 1024;
+ /* read chunks of 1 kB */
+ size_t read_bytes = 0;
+ /* Prealocate chunk */
+ unsigned char *chunk = malloc(sizeof(unsigned char) * chunk_size);
+ CHECK_ALLOC_LOG(chunk, 0);
+ while ((file_size - read_bytes) > chunk_size) {
+ if (!fread_wrapper(chunk, sizeof(unsigned char), chunk_size, f)) {
+ free(chunk);
+ return 0;
+ }
+ crc = crc_update(crc, chunk,
+ sizeof(unsigned char) * chunk_size);
+ read_bytes += chunk_size;
+ }
+
+ /* Read the rest of the file */
+ if (!fread_wrapper(chunk, sizeof(unsigned char), file_size - read_bytes,
+ f)) {
+ free(chunk);
+ return 0;
+ }
+
+ crc = crc_update(crc, chunk,
+ sizeof(unsigned char) * (file_size - read_bytes));
+ free(chunk);
+
+ fseek(f, 0L, SEEK_SET);
+ return (unsigned long)crc_finalize(crc);
+}
+
+int knot_zload_open(zloader_t **dst, const char *filename)
+{
+ *dst = 0;
+ if (!dst || !filename) {
+ return KNOT_EBADARG;
+ }
+
+ fread_wrapper = fread_safe_from_file;
+
+ /* Open file for binary read. */
+ FILE *f = fopen(filename, "rb");
+ if (unlikely(!f)) {
+ dbg_zload("knot_zload_open: failed to open '%s'\n",
+ filename);
+ return KNOT_EFEWDATA; // No such file or directory (POSIX.1)
+ }
+
+ /* Calculate CRC and compare with filename.crc file */
+ unsigned long crc_calculated = calculate_crc(f);
+
+ /* Read CRC from filename.crc file */
+ char *crc_path =
+ malloc(sizeof(char) * (strlen(filename) + strlen(".crc") + 1));
+ if (unlikely(!crc_path)) {
+ fclose(f);
+ return KNOT_ENOMEM;
+ }
+ memset(crc_path, 0,
+ sizeof(char) * (strlen(filename) + strlen(".crc") + 1));
+
+ memcpy(crc_path, filename, sizeof(char) * strlen(filename));
+
+ crc_path = strcat(crc_path, ".crc");
+ FILE *f_crc = fopen(crc_path, "r");
+ if (unlikely(!f_crc)) {
+ dbg_zload("knot_zload_open: failed to open '%s'\n",
+ crc_path);
+ fclose(f);
+ free(crc_path);
+ return KNOT_ECRC;
+ }
+
+ unsigned long crc_from_file = 0;
+ if (fscanf(f_crc, "%lu\n", &crc_from_file) != 1) {
+ dbg_zload("knot_zload_open: could not read "
+ "CRC from file '%s'\n",
+ crc_path);
+ fclose(f_crc);
+ fclose(f);
+ free(crc_path);
+ return KNOT_ERROR;
+ }
+ free(crc_path);
+ fclose(f_crc);
+
+ /* Compare calculated and read CRCs. */
+ if (crc_from_file != crc_calculated) {
+ dbg_zload("knot_zload_open: CRC failed for "
+ "file '%s'\n",
+ filename);
+ fclose(f);
+ return KNOT_ECRC;
+ }
+
+ /* Check magic sequence. */
+ static const uint8_t MAGIC[MAGIC_LENGTH] = MAGIC_BYTES;
+ if (!knot_check_magic(f, MAGIC, MAGIC_LENGTH)) {
+ fclose(f);
+ dbg_zload("knot_zload_open: magic bytes "
+ "in don't match '%*s' "
+ "(%s)\n",
+ (int)MAGIC_LENGTH, (const char*)MAGIC, filename);
+ return KNOT_EMALF; // Illegal byte sequence (POSIX.1, C99)
+ }
+
+ /* Read source file length. */
+ uint32_t sflen = 0;
+ if (!fread_wrapper(&sflen, 1, sizeof(uint32_t), f)) {
+ dbg_zload("knot_zload_open: failed to read "
+ "sfile length\n");
+ fclose(f);
+ return KNOT_ERROR;
+ }
+
+ /* Read source file. */
+ char *sfile = malloc(sflen);
+ if (!sfile) {
+ dbg_zload("knot_zload_open: invalid sfile "
+ "length %u\n", sflen);
+ fclose(f);
+ return KNOT_ENOMEM;
+ }
+ if (!fread_wrapper(sfile, 1, sflen, f)) {
+ dbg_zload("knot_zload_open: failed to read %uB "
+ "source file\n",
+ sflen);
+ free(sfile);
+ fclose(f);
+ return KNOT_ERROR;
+ }
+
+ /* Allocate new loader. */
+ zloader_t *zl = malloc(sizeof(zloader_t));
+ if (!zl) {
+ free(sfile);
+ fclose(f);
+ return KNOT_ENOMEM;
+ }
+
+ dbg_zload("knot_zload_open: opened '%s' as fp %p "
+ "(source is '%s')\n",
+ filename, f, sfile);
+ zl->filename = strdup(filename);
+ zl->source = sfile;
+ zl->fp = f;
+ *dst = zl;
+
+ return KNOT_EOK;
+}
+
+static void cleanup_id_array(knot_dname_t **id_array,
+ const uint from, const uint to)
+{
+ for (uint i = from; i < to; i++) {
+ knot_dname_release(id_array[i]);
+ }
+
+ free(id_array);
+}
+
+//static knot_dname_table_t *create_dname_table(FILE *f, uint max_id)
+//{
+// if (f == NULL ) {
+// return NULL;
+// }
+
+// if (!fread_wrapper(&max_id, sizeof(max_id), 1, f)) {
+// return NULL;
+// }
+
+// knot_dname_table_t *dname_table = knot_dname_table_new();
+// if (dname_table == NULL) {
+// return NULL;
+// }
+
+// /* Create nodes containing dnames. */
+// for (uint i = 1; i < max_id; i++) {
+// knot_dname_t *loaded_dname = read_dname_with_id(f);
+// if (loaded_dname == NULL) {
+// knot_dname_table_deep_free(&dname_table);
+// return NULL;
+// }
+// if (knot_dname_table_add_dname(dname_table,
+// loaded_dname) != KNOT_EOK) {
+
+// }
+// }
+
+// return dname_table;
+//}
+
+static knot_dname_table_t *create_dname_table_from_array(
+ knot_dname_t **array, uint max_id)
+{
+ if (array == NULL) {
+ /* should I set errno or what ... ? */
+ dbg_zload("No array passed\n");
+ return NULL;
+ }
+
+ assert(array[0] == NULL);
+
+ knot_dname_table_t *ret = knot_dname_table_new();
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ /* Table will have max_id entries */
+ for (uint i = 1; i < max_id; i++) {
+ assert(array[i]);
+ if (knot_dname_table_add_dname(ret,
+ array[i]) != KNOT_EOK) {
+ dbg_zload("Could not add: %s\n",
+ knot_dname_to_str(array[i]));
+ knot_dname_table_deep_free(&ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+static knot_dname_t **create_dname_array(FILE *f, uint max_id)
+{
+ if (f == NULL) {
+ return NULL;
+ }
+
+ knot_dname_t **array =
+ malloc(sizeof(knot_dname_t *) * ( max_id + 1));
+ memset(array, 0, sizeof(knot_dname_t *) * (max_id + 1));
+ if (array == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ for (uint i = 0; i < max_id - 1; i++) {
+ knot_dname_t *read_dname = read_dname_with_id(f);
+ if (read_dname == NULL) {
+ cleanup_id_array(array, 0, i);
+ return NULL;
+ }
+
+ if (read_dname->id < max_id) {
+
+ /* Create new node from dname. */
+ read_dname->node = knot_node_new(read_dname, NULL, 0);
+
+ if (read_dname->node == NULL) {
+ ERR_ALLOC_FAILED;
+
+ /* Release read dname. */
+ knot_dname_release(read_dname);
+ cleanup_id_array(array, 0, i);
+ return NULL;
+ }
+
+ /* Store reference to dname in array. */
+ array[read_dname->id] = read_dname;
+ } else {
+ /* Release read dname. */
+ knot_dname_release(read_dname);
+ cleanup_id_array(array, 0, i);
+ return NULL;
+ }
+
+ }
+
+ return array;
+}
+
+knot_zone_t *knot_zload_load(zloader_t *loader)
+{
+ dbg_zload("Loading zone, loader: %p\n", loader);
+ if (!loader) {
+ dbg_zload("NULL loader!\n");
+ return NULL;
+ }
+
+ fread_wrapper = fread_safe_from_file;
+
+ FILE *f = loader->fp;
+
+ knot_node_t *tmp_node;
+
+ /* Load the dname table. */
+ /* CLEANUP */
+// const knot_dname_table_t *dname_table =
+// create_dname_table(f, total_dnames);
+// if (dname_table == NULL) {
+// return NULL;
+// }
+
+ uint32_t node_count;
+ uint32_t nsec3_node_count;
+ uint32_t auth_node_count;
+
+ if (!fread_wrapper(&node_count, sizeof(node_count), 1, f)) {
+ dbg_zload("wrong read!\n");
+ return NULL;
+ }
+
+ if (!fread_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, f)) {
+ dbg_zload("wrong read!\n");
+ return NULL;
+ }
+ if (!fread_wrapper(&auth_node_count,
+ sizeof(auth_node_count), 1, f)) {
+ dbg_zload("wrong read!\n");
+ return NULL;
+ }
+ dbg_zload("authoritative nodes: %u\n", auth_node_count);
+
+ dbg_zload("loading %u nodes\n", node_count);
+
+ uint32_t total_dnames = 0;
+ /* First, read number of dnames in dname table. */
+ if (!fread_wrapper(&total_dnames, sizeof(total_dnames), 1, f)) {
+ return NULL;
+ }
+
+ dbg_zload("total dname count: %d\n", total_dnames);
+
+ /* Create id array. */
+ knot_dname_t **id_array = create_dname_array(f, total_dnames);
+ if (id_array == NULL) {
+ return NULL;
+ }
+
+ knot_dname_table_t *dname_table =
+ create_dname_table_from_array(id_array, total_dnames);
+ if (dname_table == NULL) {
+ ERR_ALLOC_FAILED;
+ cleanup_id_array(id_array, 1, total_dnames);
+ return NULL;
+ }
+
+ knot_node_t *apex = knot_load_node(f, id_array);
+
+ if (!apex) {
+ fprintf(stderr, "zone: Could not load apex node (in %s)\n",
+ loader->filename);
+ cleanup_id_array(id_array, 1,
+ node_count + nsec3_node_count + 1);
+ return NULL;
+ }
+
+ dbg_zload("Apex node loaded: %p\n", apex);
+
+ knot_zone_t *zone = knot_zone_new(apex, auth_node_count, 0);
+ if (zone == NULL) {
+ cleanup_id_array(id_array, 1,
+ node_count + nsec3_node_count + 1);
+ dbg_zload("Failed to create new zone from apex!\n");
+ return NULL;
+ }
+
+ knot_zone_contents_t *contents = knot_zone_get_contents(zone);
+ assert(contents);
+
+ /* Assign dname table to the new zone. */
+ contents->dname_table = dname_table;
+
+ /* CLEANUP */
+// apex->prev = NULL;
+ knot_node_set_previous(apex, NULL);
+
+ knot_node_t *last_node = 0;
+
+ last_node = apex;
+
+ for (uint i = 1; i < node_count; i++) {
+ tmp_node = knot_load_node(f, id_array);
+
+ if (tmp_node != NULL) {
+ if (knot_zone_contents_add_node(contents, tmp_node,
+ 0, 0, 0) != 0) {
+ fprintf(stderr, "!! cannot add node\n");
+ continue;
+ }
+ if (knot_dname_is_wildcard(tmp_node->owner)) {
+ find_and_set_wildcard_child(contents,
+ tmp_node, 0);
+ }
+
+ knot_node_set_previous(tmp_node, last_node);
+ /* CLEANUP */
+// tmp_node->prev = last_node;
+
+ if (tmp_node->rrset_count &&
+ (knot_node_is_deleg_point(tmp_node) ||
+ !knot_node_is_non_auth(tmp_node))) {
+ last_node = tmp_node;
+ }
+
+ } else {
+ fprintf(stderr, "zone: Node error (in %s).\n",
+ loader->filename);
+ }
+ }
+
+ assert(knot_node_previous(knot_zone_contents_apex(contents), 0)
+ == NULL);
+
+ knot_node_set_previous(knot_zone_contents_get_apex(contents),
+ last_node);
+
+ dbg_zload("loading %u nsec3 nodes\n", nsec3_node_count);
+
+ knot_node_t *nsec3_first = NULL;
+
+ if (nsec3_node_count > 0) {
+ nsec3_first = knot_load_node(f, id_array);
+
+ assert(nsec3_first != NULL);
+
+ if (knot_zone_contents_add_nsec3_node(contents, nsec3_first, 0, 0, 0)
+ != 0) {
+ fprintf(stderr, "!! cannot add first nsec3 node, "
+ "exiting.\n");
+ knot_zone_deep_free(&zone, 0);
+ free(id_array);
+ /* TODO this will leak dnames from id_array that were
+ * not assigned. */
+ return NULL;
+ }
+
+ knot_node_set_previous(nsec3_first, NULL);
+ /* CLEANUP */
+// nsec3_first->prev = NULL;
+
+ last_node = nsec3_first;
+ }
+
+ for (uint i = 1; i < nsec3_node_count; i++) {
+ tmp_node = knot_load_node(f, id_array);
+
+ if (tmp_node != NULL) {
+ if (knot_zone_contents_add_nsec3_node(contents,
+ tmp_node, 0, 0, 0) != 0) {
+ fprintf(stderr, "!! cannot add nsec3 node\n");
+ continue;
+ }
+
+ knot_node_set_previous(tmp_node, last_node);
+ /* CLEANUP */
+// tmp_node->prev = last_node;
+
+ last_node = tmp_node;
+ } else {
+ fprintf(stderr, "zone: Node error (in %s).\n",
+ loader->filename);
+ }
+ }
+
+ if (nsec3_node_count) {
+ assert(knot_node_previous(nsec3_first, 0) == NULL);
+ knot_node_set_previous(nsec3_first, last_node);
+ /* CLEANUP */
+// nsec3_first->prev = last_node;
+ }
+
+ /* ID array is now useless */
+ for (uint i = 1; i < total_dnames; i++) {
+ /* Added to table, may discard now. */
+ knot_dname_release(id_array[i]);
+ }
+ free(id_array);
+
+ dbg_zload("zone loaded, returning: %p\n", zone);
+ return zone;
+}
+
+int knot_zload_needs_update(zloader_t *loader)
+{
+ if (!loader) {
+ return 1;
+ }
+
+ /* Check if the source still exists. */
+ struct stat st_src;
+ if (stat(loader->source, &st_src) != 0) {
+ return 1;
+ }
+
+ /* Check if the compiled file still exists. */
+ struct stat st_bin;
+ if (stat(loader->filename, &st_bin) != 0) {
+ return 1;
+ }
+
+ /* Compare the mtime of the source and file. */
+ /*! \todo Inspect types on Linux. */
+ if (timet_cmp(st_bin.st_mtime, st_src.st_mtime) < 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void knot_zload_close(zloader_t *loader)
+{
+ if (!loader) {
+ return;
+ }
+
+ free(loader->filename);
+ free(loader->source);
+ fclose(loader->fp);
+ free(loader);
+}
+
+int knot_zload_rrset_deserialize(knot_rrset_t **rrset,
+ uint8_t *stream, size_t *size)
+{
+ if (stream == NULL || size == 0) {
+ return KNOT_EBADARG;
+ }
+
+ fread_wrapper = read_from_stream;
+
+ knot_zload_stream = stream;
+ knot_zload_stream_remaining = knot_zload_stream_size = *size;
+
+ knot_rrset_t *ret = knot_load_rrset(NULL, NULL, 0);
+
+ if (ret == NULL) {
+ knot_zload_stream = NULL;
+ knot_zload_stream_remaining = 0;
+ knot_zload_stream_size = 0;
+ return KNOT_EMALF;
+ }
+
+ *size = knot_zload_stream_remaining;
+ *rrset = ret;
+
+ knot_zload_stream = NULL;
+ knot_zload_stream_remaining = 0;
+ knot_zload_stream_size = 0;
+
+ return KNOT_EOK;
+}
+
diff --git a/src/knot/zone/zone-load.h b/src/knot/zone/zone-load.h
new file mode 100644
index 0000000..2fe318f
--- /dev/null
+++ b/src/knot/zone/zone-load.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file zone-load.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief Loader of previously parsed zone
+ *
+ * \addtogroup dnslib
+ * @{
+ */
+
+#ifndef _KNOT_ZONELOAD_H_
+#define _KNOT_ZONELOAD_H_
+
+#include <stdio.h>
+
+#include "libknot/zone/zone.h"
+
+/*!
+ * \brief Zone loader structure.
+ */
+typedef struct zloader_t
+{
+ char *filename; /*!< Compiled zone filename. */
+ char *source; /*!< Zone source file. */
+ FILE *fp; /*!< Open filepointer to compiled zone. */
+
+} zloader_t;
+
+/*!
+ * \brief Initializes zone loader from file..
+ *
+ * \param filename File containing the compiled zone.
+ * \param loader Will create new loader in *loader.
+ *
+ * \retval Initialized loader on success.
+ * \retval NULL on error.
+ */
+int knot_zload_open(zloader_t **loader, const char *filename);
+
+/*!
+ * \brief Loads zone from a compiled and serialized zone file.
+ *
+ * \param loader Zone loader instance.
+ *
+ * \retval Loaded zone on success.
+ * \retval NULL otherwise.
+ */
+knot_zone_t *knot_zload_load(zloader_t *loader);
+
+/*!
+ * \brief Checks whether the compiled zone needs a recompilation.
+ *
+ * \param loader Zone loader instance.
+ *
+ * \retval 1 is if needs to be recompiled.
+ * \retval 0 if it is up to date.
+ */
+int knot_zload_needs_update(zloader_t *loader);
+
+
+/*!
+ * \brief Free zone loader.
+ *
+ * \param loader Zone loader instance.
+ */
+void knot_zload_close(zloader_t *loader);
+
+/*!
+ * \brief Loads RRSet serialized by knot_zdump_rrset_serialize().
+ *
+ * \param stream Stream containing serialized RRSet.
+ * \param size Size of stream. This variable will contain remaining length of
+ * stream, once the function has ended.
+ * \param rrset Place for created RRSet.
+ *
+ * \note If RRSet contains RRSIGs, their owners are not copies, but only links
+ * to the owner of RRSet. All RDATA dnames are copied.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EBADAG on wrong arguments.
+ * \retval KNOT_EMALF when stream is malformed.
+ */
+int knot_zload_rrset_deserialize(knot_rrset_t **rrset,
+ uint8_t *stream, size_t *size);
+
+#endif /* _KNOTD_ZONELOAD_H_ */
+
+/*! @} */
diff --git a/src/knotc.8 b/src/knotc.8
new file mode 100644
index 0000000..f2e7e40
--- /dev/null
+++ b/src/knotc.8
@@ -0,0 +1,63 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4.
+.TH KNOT "1" "November 2011" "Knot DNS, version 0.8" "User Commands"
+.SH NAME
+Knot \- manual page for Knot DNS, version 0.8
+.SH SYNOPSIS
+.B knotc
+[\fIparameters\fR] \fIstart|stop|restart|reload|running|compile\fR
+.SH DESCRIPTION
+.SS "Parameters:"
+.HP
+\fB\-c\fR [file], \fB\-\-config\fR=\fI[file]\fR Select configuration file.
+.TP
+\fB\-j\fR [num], \fB\-\-jobs\fR=\fI[num]\fR
+Number of parallel tasks to run (only for 'compile').
+.TP
+\fB\-f\fR, \fB\-\-force\fR
+Force operation \- override some checks.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+Verbose mode \- additional runtime information.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+Print knot server version.
+.TP
+\fB\-w\fR, \fB\-\-wait\fR
+Wait for the server to finish start/stop operations.
+.TP
+\fB\-i\fR, \fB\-\-interactive\fR
+Interactive mode (do not daemonize).
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Print help and usage.
+.SS "Actions:"
+.TP
+start
+Start knot server zone (no\-op if running).
+.TP
+stop
+Stop knot server (no\-op if not running).
+.TP
+restart
+Stops and then starts knot server.
+.TP
+reload
+Reload knot configuration and compiled zones.
+.TP
+running
+check if server is running.
+.TP
+compile
+Compile zone file.
+.SH "SEE ALSO"
+The full documentation for
+.B Knot
+is maintained as a Texinfo manual. If the
+.B info
+and
+.B Knot
+programs are properly installed at your site, the command
+.IP
+.B info Knot
+.PP
+should give you access to the complete manual.
diff --git a/src/knotd.8 b/src/knotd.8
new file mode 100644
index 0000000..3275e9b
--- /dev/null
+++ b/src/knotd.8
@@ -0,0 +1,35 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4.
+.TH KNOT "1" "November 2011" "Knot DNS, version 0.8" "User Commands"
+.SH NAME
+Knot \- manual page for Knot DNS, version 0.8
+.SH SYNOPSIS
+.B knotd
+[\fIparameters\fR]
+.SH DESCRIPTION
+.SS "Parameters:"
+.HP
+\fB\-c\fR, \fB\-\-config\fR [file] Select configuration file.
+.TP
+\fB\-d\fR, \fB\-\-daemonize\fR
+Run server as a daemon.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+Verbose mode \- additional runtime information.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+Print version of the server.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Print help and usage.
+.SH "SEE ALSO"
+The full documentation for
+.B Knot
+is maintained as a Texinfo manual. If the
+.B info
+and
+.B Knot
+programs are properly installed at your site, the command
+.IP
+.B info Knot
+.PP
+should give you access to the complete manual.
diff --git a/src/libknot/common.h b/src/libknot/common.h
new file mode 100644
index 0000000..9b2d8ae
--- /dev/null
+++ b/src/libknot/common.h
@@ -0,0 +1,105 @@
+/*!
+ * \file common.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Common macros, includes and utilities.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_LIBLDNS
+#define TEST_WITH_LDNS
+#endif
+
+#ifndef _KNOT_COMMON_H_
+#define _KNOT_COMMON_H_
+
+#define KNOT_NAME "lib" PACKAGE_NAME // Project name
+#define KNOT_VER PACKAGE_VERSION // 0xMMIIRR (MAJOR,MINOR,REVISION)
+
+#ifndef UINT_DEFINED
+typedef unsigned int uint; /*!< \brief Unsigned. */
+#define UINT_DEFINED
+#endif
+
+/*! \brief If defined, zone structures will use hash table for lookup. */
+#define USE_HASH_TABLE
+
+/*! \brief Eliminate compiler warning with unused parameters. */
+#define UNUSED(param) (void)(param)
+
+/*! \brief Type-safe minimum macro. */
+#define MIN(a, b) \
+ ({ typeof (a) _a = (a); typeof (b) _b = (b); _a < _b ? _a : _b; })
+
+/*! \brief Type-safe maximum macro. */
+#define MAX(a, b) \
+ ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; })
+
+/* Optimisation macros. */
+#ifndef likely
+/*! \brief Optimize for x to be true value. */
+#define likely(x) __builtin_expect((x),1)
+#endif
+#ifndef unlikely
+/*! \brief Optimize for x to be false value. */
+#define unlikely(x) __builtin_expect((x),0)
+#endif
+
+/* Optimisation macros. */
+#ifndef likely
+/*! \brief Optimize for x to be true value. */
+#define likely(x) __builtin_expect((x),1)
+#endif
+#ifndef unlikely
+/*! \brief Optimize for x to be false value. */
+#define unlikely(x) __builtin_expect((x),0)
+#endif
+
+/*! \todo Refactor theese. We should have an allocator function handling this.*/
+#ifndef ERR_ALLOC_FAILED
+#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d (%s ver.%s)\n", \
+ __FILE__, __LINE__, KNOT_NAME, KNOT_VER)
+#endif
+
+#ifndef CHECK_ALLOC_LOG
+#define CHECK_ALLOC_LOG(var, ret) \
+ do { \
+ if ((var) == NULL) { \
+ ERR_ALLOC_FAILED; \
+ return (ret); \
+ } \
+ } while (0)
+#endif
+
+#ifndef CHECK_ALLOC
+#define CHECK_ALLOC(var, ret) \
+ do { \
+ if ((var) == NULL) { \
+ return (ret); \
+ } \
+ } while (0)
+#endif
+
+#endif /* _KNOT_COMMON_H_ */
+
+/*! @} */
diff --git a/src/libknot/consts.h b/src/libknot/consts.h
new file mode 100644
index 0000000..4249763
--- /dev/null
+++ b/src/libknot/consts.h
@@ -0,0 +1,108 @@
+/*!
+ * \file consts.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Contains some DNS-related constants.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_CONSTS_H_
+#define _KNOT_CONSTS_H_
+
+#include <stdint.h>
+#include "util/descriptor.h"
+
+/*
+ * OPCODEs
+ */
+typedef enum knot_opcode {
+ KNOT_OPCODE_QUERY = 0, /* a standard query (QUERY) */
+ KNOT_OPCODE_IQUERY = 1, /* an inverse query (IQUERY) */
+ KNOT_OPCODE_STATUS = 2, /* a server status request (STATUS) */
+ KNOT_OPCODE_NOTIFY = 4, /* NOTIFY */
+ KNOT_OPCODE_UPDATE = 5, /* Dynamic update */
+ KNOT_OPCODE_OFFSET = 14
+} knot_opcode_t;
+
+/*!
+ * \brief Query types (internal use only).
+ *
+ * This type encompasses the different query types distinguished by both the
+ * OPCODE and the QTYPE.
+ */
+typedef enum knot_packet_type {
+ KNOT_QUERY_NORMAL, /*!< Normal query. */
+ KNOT_QUERY_AXFR, /*!< Request for AXFR transfer. */
+ KNOT_QUERY_IXFR, /*!< Request for IXFR transfer. */
+ KNOT_QUERY_NOTIFY, /*!< NOTIFY query. */
+ KNOT_QUERY_UPDATE, /*!< Dynamic update. */
+ KNOT_RESPONSE_NORMAL, /*!< Normal response. */
+ KNOT_RESPONSE_AXFR, /*!< AXFR transfer response. */
+ KNOT_RESPONSE_IXFR, /*!< IXFR transfer response. */
+ KNOT_RESPONSE_NOTIFY /*!< NOTIFY response. */
+} knot_packet_type_t;
+
+/*
+ * RCODEs
+ */
+typedef enum knot_rcode {
+ KNOT_RCODE_NOERROR = 0, /* No error condition */
+ KNOT_RCODE_FORMERR = 1, /* Format error */
+ KNOT_RCODE_SERVFAIL = 2, /* Server failure */
+ KNOT_RCODE_NXDOMAIN = 3, /* Name Error */
+ KNOT_RCODE_NOTIMPL = 4, /* Not implemented */
+ KNOT_RCODE_REFUSED = 5, /* Refused */
+ KNOT_RCODE_YXDOMAIN = 6, /* name should not exist */
+ KNOT_RCODE_YXRRSET = 7, /* rrset should not exist */
+ KNOT_RCODE_NXRRSET = 8, /* rrset does not exist */
+ KNOT_RCODE_NOTAUTH = 9, /* server not authoritative */
+ KNOT_RCODE_NOTZONE = 10, /* name not inside zone */
+} knot_rcode_t;
+
+typedef enum knot_tsig_rcode {
+ KNOT_TSIG_RCODE_BADSIG = 16,
+ KNOT_TSIG_RCODE_BADKEY = 17,
+ KNOT_TSIG_RCODE_BADTIME = 18
+} knot_tsig_rcode_t;
+
+/*
+ * CLASSes
+ */
+//typedef enum knot_class {
+// KNOT_CLASS_IN = 1, /* Class IN */
+// KNOT_CLASS_CS = 2, /* Class CS */
+// KNOT_CLASS_CH = 3, /* Class CHAOS */
+// KNOT_CLASS_HS = 4, /* Class HS */
+// KNOT_CLASS_NONE = 254, /* Class NONE rfc2136 */
+// KNOT_CLASS_ANY = 255 /* Class ANY */
+//} knot_class_t;
+
+/*
+ * Other
+ */
+typedef enum knot_const {
+ KNOT_MAX_DNAME_LENGTH = 255,
+ KNOT_MAX_DNAME_LABELS = 127 // 1-char labels
+} knot_const_t;
+
+#endif /* _KNOT_CONSTS_H_ */
+
+/*! @} */
diff --git a/src/libknot/dname.c b/src/libknot/dname.c
new file mode 100644
index 0000000..869b342
--- /dev/null
+++ b/src/libknot/dname.c
@@ -0,0 +1,1070 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h> // tolower()
+
+#include "common.h"
+#include "util/error.h"
+#include "dname.h"
+#include "consts.h"
+#include "util/tolower.h"
+#include "util/debug.h"
+#include "util/utils.h"
+#include "util/wire.h"
+
+/*! \todo dnames allocated from TLS cache will be discarded after thread
+ * termination. This shouldn't happpen.
+ */
+#if 0
+/*
+ * Memory cache.
+ */
+#include "common/slab/slab.h"
+#include <stdio.h>
+#include <pthread.h>
+
+/*! \brief TLS unique key for each thread cache. */
+static pthread_key_t dname_ckey;
+static pthread_once_t dname_once = PTHREAD_ONCE_INIT;
+
+/*! \brief Destroy thread dname cache (automatically called). */
+static void knot_dname_cache_free(void *ptr)
+{
+ slab_cache_t* cache = (slab_cache_t*)ptr;
+ if (cache) {
+ slab_cache_destroy(cache);
+ free(cache);
+ }
+}
+
+/*! \brief Cleanup for main() TLS. */
+static void knot_dname_cache_main_free()
+{
+ knot_dname_cache_free(pthread_getspecific(dname_ckey));
+}
+
+static void knot_dname_cache_init()
+{
+ (void) pthread_key_create(&dname_ckey, knot_dname_cache_free);
+ atexit(knot_dname_cache_main_free); // Main thread cleanup
+}
+#endif
+
+/*!
+ * \brief Allocate item from thread cache.
+ * \retval Allocated dname instance on success.
+ * \retval NULL on error.
+ */
+static knot_dname_t* knot_dname_alloc()
+{
+ return malloc(sizeof(knot_dname_t));
+
+ /*! \todo dnames allocated from TLS cache will be discarded after thread
+ * termination. This shouldn't happpen.
+ */
+#if 0
+ /* Initialize dname cache TLS key. */
+ (void)pthread_once(&dname_once, knot_dname_cache_init);
+
+ /* Create cache if not exists. */
+ slab_cache_t* cache = pthread_getspecific(dname_ckey);
+ if (unlikely(!cache)) {
+ cache = malloc(sizeof(slab_cache_t));
+ if (!cache) {
+ return 0;
+ }
+
+ /* Initialize cache. */
+ slab_cache_init(cache, sizeof(knot_dname_t));
+ (void)pthread_setspecific(dname_ckey, cache);
+ }
+
+ return slab_cache_alloc(cache);
+#endif
+}
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+
+static int knot_dname_set(knot_dname_t *dname, uint8_t *wire,
+ short wire_size, const uint8_t *labels,
+ short label_count)
+{
+ dname->name = wire;
+ dname->size = wire_size;
+ dname->label_count = label_count;
+
+ assert(label_count >= 0);
+
+ dname->labels = (uint8_t *)malloc(dname->label_count * sizeof(uint8_t));
+ CHECK_ALLOC_LOG(dname->labels, -1);
+ memcpy(dname->labels, labels, dname->label_count);
+
+ return 0;
+}
+
+/*!
+ * \brief Converts domain name from string representation to wire format.
+ *
+ * This function also allocates the space for the wire format.
+ *
+ * \param name Domain name in string representation (presentation format).
+ * \param size Size of the given domain name in characters (not counting the
+ * terminating 0 character.
+ * \param dname Domain name where to store the wire format.
+ *
+ * \return Size of the wire format of the domain name in octets. If 0, no
+ * space has been allocated.
+ *
+ * \todo handle \X and \DDD (RFC 1035 5.1) or it can be handled by the parser?
+ */
+static int knot_dname_str_to_wire(const char *name, uint size,
+ knot_dname_t *dname)
+{
+ if (size > KNOT_MAX_DNAME_LENGTH) {
+ return -1;
+ }
+
+ uint wire_size;
+ int root = (*name == '.' && size == 1);
+ // root => different size
+ if (root) {
+ wire_size = 1;
+ } else {
+ wire_size = size + 1;
+ }
+
+ uint8_t *wire;
+ uint8_t labels[KNOT_MAX_DNAME_LABELS];
+ short label_count = 0;
+
+ // signed / unsigned issues??
+ wire = (uint8_t *)malloc(wire_size * sizeof(uint8_t));
+ if (wire == NULL) {
+ return -1;
+ }
+
+ dbg_dname("Allocated space for wire format of dname: %p\n",
+ wire);
+
+ if (root) {
+ *wire = '\0';
+ label_count = 0;
+ return knot_dname_set(dname, wire, wire_size, labels,
+ label_count);
+ }
+
+ const uint8_t *ch = (const uint8_t *)name;
+ uint8_t *label_start = wire;
+ uint8_t *w = wire + 1;
+ uint8_t label_length = 0;
+
+ while (ch - (const uint8_t *)name < size) {
+ assert(w - wire - 1 == ch - (const uint8_t *)name);
+
+ if (*ch == '.') {
+ dbg_dname("Position %zd (%p): "
+ "label length: %u\n",
+ label_start - wire,
+ label_start, label_length);
+ *label_start = label_length;
+ labels[label_count++] = label_start - wire;
+ label_start = w;
+ label_length = 0;
+ } else {
+ assert(w - wire < wire_size);
+ dbg_dname("Position %zd (%p): character: %c\n",
+ w - wire, w, *ch);
+ *w = *ch;
+ ++label_length;
+ }
+
+ ++w;
+ ++ch;
+ assert(ch >= (const uint8_t *)name);
+ }
+
+ --ch;
+ if (*ch == '.') { // put 0 for root label if the name ended with .
+ --w;
+ dbg_dname("Position %zd (%p): character: (null)\n",
+ w - wire, w);
+ *w = 0;
+ } else { // otherwise we did not save the last label length
+ dbg_dname("Position %zd (%p): "
+ "label length: %u\n",
+ label_start - wire,
+ label_start, label_length);
+ *label_start = label_length;
+ labels[label_count++] = label_start - wire;
+ }
+
+ return knot_dname_set(dname, wire, wire_size, labels, label_count);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static inline int knot_dname_tolower(uint8_t c, int cs)
+{
+ return (cs) ? c : knot_tolower(c);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_dname_compare_labels(const uint8_t *label1,
+ const uint8_t *label2, int cs)
+{
+ const uint8_t *pos1 = label1;
+ const uint8_t *pos2 = label2;
+
+ int label_length = (*pos1 < *pos2) ? *pos1 : *pos2;
+ int i = 0;
+
+ while (i < label_length
+ && knot_dname_tolower(*(++pos1), cs)
+ == knot_dname_tolower(*(++pos2), cs)) {
+ ++i;
+ }
+
+ if (i < label_length) { // difference in some octet
+ return (knot_dname_tolower(*pos1, cs)
+ - knot_dname_tolower(*pos2, cs));
+ }
+
+ return (label1[0] - label2[0]);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_dname_find_labels(knot_dname_t *dname, int alloc)
+{
+ const uint8_t *name = dname->name;
+ const uint8_t *pos = name;
+ const uint size = dname->size;
+
+ uint8_t labels[KNOT_MAX_DNAME_LABELS];
+ short label_count = 0;
+
+ while (pos - name < size && *pos != '\0') {
+ labels[label_count++] = pos - name;
+ pos += *pos + 1;
+ }
+
+ // TODO: how to check if the domain name has right format?
+ if (pos - name > size || *pos != '\0') {
+ dbg_dname("Wrong wire format of domain name!\n");
+ dbg_dname("Position: %d, character: %d, expected"
+ " size: %d\n", pos - name, *pos, size);
+ return -1;
+ }
+
+ if (alloc) {
+ dname->labels
+ = (uint8_t *)malloc(label_count * sizeof(uint8_t));
+ CHECK_ALLOC_LOG(dname->labels, KNOT_ENOMEM);
+ }
+
+ memcpy(dname->labels, labels, label_count);
+ dname->label_count = label_count;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2,
+ int cs)
+{
+dbg_dname_exec(
+ char *name1 = knot_dname_to_str(d1);
+ char *name2 = knot_dname_to_str(d2);
+
+ dbg_dname("Comparing dnames %s and %s\n",
+ name1, name2);
+
+ for (int i = 0; i < strlen(name1); ++i) {
+ name1[i] = knot_tolower(name1[i]);
+ }
+ for (int i = 0; i < strlen(name2); ++i) {
+ name2[i] = knot_tolower(name2[i]);
+ }
+
+ dbg_dname("After to lower: %s and %s\n",
+ name1, name2);
+
+ free(name1);
+ free(name2);
+);
+
+ if (!cs && d1 == d2) {
+ return 0;
+ }
+
+ int l1 = d1->label_count;
+ int l2 = d2->label_count;
+ dbg_dname("Label counts: %d and %d\n", l1, l2);
+ assert(l1 >= 0);
+ assert(l2 >= 0);
+
+ // compare labels from last to first
+ while (l1 > 0 && l2 > 0) {
+ dbg_dname("Comparing labels %d and %d\n",
+ l1 - 1, l2 - 1);
+ dbg_dname(" at offsets: %d and %d\n",
+ d1->labels[l1 - 1], d2->labels[l2 - 1]);
+ int res = knot_dname_compare_labels(
+ &d1->name[d1->labels[--l1]],
+ &d2->name[d2->labels[--l2]],
+ cs);
+ if (res != 0) {
+ return res;
+ } // otherwise the labels are identical, continue with previous
+ }
+
+ // if all labels matched, the shorter name is first
+ if (l1 == 0 && l2 > 0) {
+ return -1;
+ }
+
+ if (l1 > 0 && l2 == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*! \brief Destructor for reference counter. */
+static void knot_dname_dtor(struct ref_t *p)
+{
+ knot_dname_t *dname = (knot_dname_t *)p;
+ knot_dname_free(&dname);
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_dname_new()
+{
+ knot_dname_t *dname = knot_dname_alloc();
+ dname->name = NULL;
+ dname->size = 0;
+ dname->node = NULL;
+ dname->labels = NULL;
+ dname->label_count = -1;
+ dname->id = 0;
+
+ /* Initialize reference counting. */
+ ref_init(&dname->ref, knot_dname_dtor);
+
+ /* Set reference counter to 1, caller should release it after use. */
+ knot_dname_retain(dname);
+
+ return dname;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_dname_new_from_str(const char *name, uint size,
+ struct knot_node *node)
+{
+ if (name == NULL || size == 0) {
+ return NULL;
+ }
+
+// knot_dname_t *dname = knot_dname_alloc();
+ knot_dname_t *dname = knot_dname_new();
+
+ if (dname == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ knot_dname_str_to_wire(name, size, dname);
+ dbg_dname("Created dname with size: %d\n", dname->size);
+ dbg_dname("Label offsets: ");
+ for (int i = 0; i < dname->label_count; ++i) {
+ dbg_dname("%d, ", dname->labels[i]);
+ }
+ dbg_dname("\n");
+
+ if (dname->size <= 0) {
+ fprintf(stderr, "Could not parse domain name "
+ "from string: '%.*s'\n", size, name);
+ }
+ assert(dname->name != NULL);
+
+ dname->node = node;
+ dname->id = 0;
+
+ return dname;
+}
+
+/*----------------------------------------------------------------------------*/
+
+//int knot_dname_from_wire(knot_dname_t *dname, const uint8_t *name,
+// uint size)
+//{
+// int i = 0;
+// uint8_t labels[KNOT_MAX_DNAME_LABELS];
+// int label_i = 0;
+
+// while (name[i] != 0) {
+// labels[label_i++] = i;
+// uint8_t label_length = name[i];
+// if (i + label_length >= size) {
+// return -2;
+// }
+// for (int j = 1; j <= label_length; ++j) {
+// }
+// }
+//}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size,
+ struct knot_node *node)
+{
+ if (name == NULL) { /* && size != 0) { !OS: Nerozumjaju */
+ dbg_dname("No name given!\n");
+ return NULL;
+ }
+
+ knot_dname_t *dname = knot_dname_new();
+
+ if (dname == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ dname->name = (uint8_t *)malloc(size * sizeof(uint8_t));
+ if (dname->name == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_dname_free(&dname);
+ return NULL;
+ }
+
+ memcpy(dname->name, name, size);
+ dname->size = size;
+
+ if (knot_dname_find_labels(dname, 1) != 0) {
+ knot_dname_free(&dname);
+ return NULL;
+ }
+
+ dname->node = node;
+ dname->id = 0;
+
+ return dname;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
+ size_t *pos, size_t size,
+ knot_node_t *node)
+{
+ uint8_t name[KNOT_MAX_DNAME_LENGTH];
+ uint8_t labels[KNOT_MAX_DNAME_LABELS];
+
+ short l = 0;
+ size_t i = 0, p = *pos;
+ int pointer_used = 0;
+
+ while (p < size && wire[p] != 0) {
+ labels[l] = i;
+ dbg_dname("Next label (%d.) position: %zu\n", l, i);
+
+ if (knot_wire_is_pointer(wire + p)) {
+ // pointer.
+// printf("Pointer.\n");
+ p = knot_wire_get_pointer(wire + p);
+ if (!pointer_used) {
+ *pos += 2;
+ pointer_used = 1;
+ }
+ if (p >= size) {
+ return NULL;
+ }
+ } else {
+ // label; first byte is label length
+ uint8_t length = *(wire + p);
+// printf("Label, length: %u.\n", length);
+ memcpy(name + i, wire + p, length + 1);
+ p += length + 1;
+ i += length + 1;
+ if (!pointer_used) {
+ *pos += length + 1;
+ }
+ ++l;
+ }
+ }
+ if (p >= size) {
+ return NULL;
+ }
+
+ name[i] = 0;
+ if (!pointer_used) {
+ *pos += 1;
+ }
+
+ knot_dname_t *dname = knot_dname_new();
+
+ if (dname == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ dname->name = (uint8_t *)malloc((i + 1) * sizeof(uint8_t));
+ if (dname->name == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_dname_free(&dname);
+ return NULL;
+ }
+
+ memcpy(dname->name, name, i + 1);
+ dname->size = i + 1;
+
+ dname->labels = (uint8_t *)malloc((l + 1) * sizeof(uint8_t));
+ if (dname->labels == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_dname_free(&dname);
+ return NULL;
+ }
+ memcpy(dname->labels, labels, l + 1);
+
+ dname->label_count = l;
+
+ dname->node = node;
+
+ return dname;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_from_wire(const uint8_t *name, uint size,
+ struct knot_node *node, knot_dname_t *target)
+{
+ if (name == NULL || target == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ memcpy(target->name, name, size);
+ target->size = size;
+ target->node = node;
+ target->id = 0;
+
+ return knot_dname_find_labels(target, 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname)
+{
+ return knot_dname_new_from_wire(dname->name, dname->size,
+ dname->node);
+}
+
+/*----------------------------------------------------------------------------*/
+
+char *knot_dname_to_str(const knot_dname_t *dname)
+{
+ if (!dname || dname->size == 0) {
+ return 0;
+ }
+
+ char *name;
+
+ // root => special treatment
+ if (dname->size == 1) {
+ assert(dname->name[0] == 0);
+ name = (char *)malloc(2 * sizeof(char));
+ name[0] = '.';
+ name[1] = '\0';
+ return name;
+ }
+
+ name = (char *)malloc(dname->size * sizeof(char));
+ if (name == NULL) {
+ return NULL;
+ }
+
+ uint8_t *w = dname->name;
+ char *ch = name;
+ int i = 0;
+
+ do {
+ assert(*w != 0);
+ int label_size = *(w++);
+ // copy the label
+ memcpy(ch, w, label_size);
+ i += label_size;
+ ch += label_size;
+ w += label_size;
+ if (w - dname->name < dname->size) { // another label following
+ *(ch++) = '.';
+ ++i;
+ }
+ } while (i < dname->size - 1);
+
+ *ch = 0;
+ assert(ch - name == dname->size - 1);
+
+ return name;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_to_lower(knot_dname_t *dname)
+{
+ if (dname == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ for (int i = 0; i < dname->size; ++i) {
+ dname->name[i] = knot_tolower(dname->name[i]);
+ }
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name,
+ size_t size)
+{
+ if (dname == NULL || name == NULL || size < dname->size) {
+ return KNOT_EBADARG;
+ }
+
+ for (int i = 0; i < dname->size; ++i) {
+ name[i] = knot_tolower(dname->name[i]);
+ }
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const uint8_t *knot_dname_name(const knot_dname_t *dname)
+{
+ return dname->name;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint knot_dname_size(const knot_dname_t *dname)
+{
+ return dname->size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+unsigned int knot_dname_id(const knot_dname_t *dname)
+{
+ return dname->id;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint8_t knot_dname_size_part(const knot_dname_t *dname, int labels)
+{
+ assert(labels < dname->label_count);
+ assert(dname->labels != NULL);
+ return (dname->labels[labels]);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const struct knot_node *knot_dname_node(const knot_dname_t *dname,
+ int check_version)
+
+{
+ if (check_version) {
+ return knot_node_current(dname->node);
+ } else {
+ return dname->node;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+struct knot_node *knot_dname_get_node(knot_dname_t *dname,
+ int check_version)
+{
+ if (check_version) {
+ return knot_node_get_current(dname->node);
+ } else {
+ return dname->node;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_dname_set_node(knot_dname_t *dname, knot_node_t *node)
+{
+ dname->node = node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_dname_update_node(knot_dname_t *dname)
+{
+ knot_node_update_ref(&dname->node);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_is_fqdn(const knot_dname_t *dname)
+{
+ return (dname->name[dname->size - 1] == '\0');
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname)
+{
+ knot_dname_t *parent = knot_dname_new();
+ if (parent == NULL) {
+ return NULL;
+ }
+
+ parent->size = dname->size - dname->name[0] - 1;
+ parent->name = (uint8_t *)malloc(parent->size);
+ if (parent->name == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_dname_free(&parent);
+ return NULL;
+ }
+
+ parent->labels = (uint8_t *)malloc(dname->label_count - 1);
+ if (parent->labels == NULL) {
+ ERR_ALLOC_FAILED;
+ free(parent->name);
+ knot_dname_free(&parent);
+ return NULL;
+ }
+
+ memcpy(parent->name, &dname->name[dname->name[0] + 1], parent->size);
+
+ short first_label_length = dname->labels[1];
+
+ for (int i = 0; i < dname->label_count - 1; ++i) {
+ parent->labels[i] = dname->labels[i + 1] - first_label_length;
+ }
+ parent->label_count = dname->label_count - 1;
+
+ return parent;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_dname_left_chop_no_copy(knot_dname_t *dname)
+{
+ // copy the name
+ short first_label_length = dname->labels[1];
+
+ if (dname->label_count > 1) {
+ memmove(dname->name, &dname->name[dname->labels[1]],
+ dname->size - first_label_length);
+ // adjust labels
+ for (int i = 0; i < dname->label_count - 1; ++i) {
+ dname->labels[i] = dname->labels[i + 1]
+ - first_label_length;
+ }
+ dname->label_count = dname->label_count - 1;
+ dname->size -= first_label_length;
+ } else {
+ dname->name[0] = '\0';
+ dname->size = 1;
+ dname->label_count = 0;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_is_subdomain(const knot_dname_t *sub,
+ const knot_dname_t *domain)
+{
+dbg_dname_exec(
+ char *name1 = knot_dname_to_str(sub);
+ char *name2 = knot_dname_to_str(domain);
+
+ dbg_dname("Checking if %s is subdomain of %s\n",
+ name1, name2);
+ free(name1);
+ free(name2);
+);
+
+ if (sub == domain) {
+ return 0;
+ }
+
+ // if one of the names is fqdn and the other is not
+ if ((sub->name[sub->size - 1] == '\0'
+ && domain->name[domain->size - 1] != '\0')
+ || (sub->name[sub->size - 1] != '\0'
+ && domain->name[domain->size - 1] == '\0')) {
+ return 0;
+ }
+
+ int l1 = sub->label_count;
+ int l2 = domain->label_count;
+
+ dbg_dname("Label counts: %d and %d\n", l1, l2);
+
+ if (l1 <= l2) { // if sub does not have more labes than domain
+ return 0; // it is not its subdomain
+ }
+
+ // compare labels from last to first
+ while (l1 > 0 && l2 > 0) {
+ dbg_dname("Comparing labels %d and %d\n",
+ l1 - 1, l2 - 1);
+ dbg_dname(" at offsets: %d and %d\n",
+ sub->labels[l1 - 1], domain->labels[l2 - 1]);
+ // if some labels do not match
+ if (knot_dname_compare_labels(&sub->name[sub->labels[--l1]],
+ &domain->name[domain->labels[--l2]], 0)
+ != 0) {
+ return 0; // sub is not a subdomain of domain
+ } // otherwise the labels are identical, continue with previous
+ }
+
+ // if all labels matched, it should be subdomain (more labels)
+ assert(l1 > l2);
+
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_is_wildcard(const knot_dname_t *dname)
+{
+ return (dname->size >= 2
+ && dname->name[0] == 1
+ && dname->name[1] == '*');
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_matched_labels(const knot_dname_t *dname1,
+ const knot_dname_t *dname2)
+{
+ int l1 = dname1->label_count;
+ int l2 = dname2->label_count;
+
+ // compare labels from last to first
+ int matched = 0;
+ while (l1 > 0 && l2 > 0) {
+ int res = knot_dname_compare_labels(
+ &dname1->name[dname1->labels[--l1]],
+ &dname2->name[dname2->labels[--l2]], 0);
+ if (res == 0) {
+ ++matched;
+ } else {
+ break;
+ }
+ }
+
+ return matched;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_label_count(const knot_dname_t *dname)
+{
+ return dname->label_count;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint8_t knot_dname_label_size(const knot_dname_t *dname, int i)
+{
+// printf("Returning size of %d. label starting on %d\n",
+// i, dname->labels[i]);
+// printf("Label count: %d, size of %d. label: %d, size of %d.label: %d\n",
+// dname->label_count, i, dname->labels[i], i + 1,
+// dname->labels[i+1]);
+// printf("Size from the name: %u\n", dname->name[dname->labels[i]]);
+// printf("Size from label offsets: %u\n",
+// dname->labels[i + 1] - dname->labels[i]);
+
+ assert(i >= 0);
+ assert(dname->size == 1 || i + 1 == dname->label_count
+ || dname->labels[i + 1] - dname->labels[i] - 1
+ == dname->name[dname->labels[i]]);
+ return dname->name[dname->labels[i]];
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname,
+ int size,
+ const knot_dname_t *suffix)
+{
+dbg_dname_exec(
+ char *name = knot_dname_to_str(dname);
+ dbg_dname("Replacing suffix of name %s, size %d with ", name,
+ size);
+ free(name);
+ name = knot_dname_to_str(suffix);
+ dbg_dname("%s (size %d)\n", name, suffix->size);
+ free(name);
+);
+ knot_dname_t *res = knot_dname_new();
+ CHECK_ALLOC(res, NULL);
+
+ res->size = dname->size - size + suffix->size;
+
+ dbg_dname("Allocating %d bytes...\n", res->size);
+ res->name = (uint8_t *)malloc(res->size);
+ if (res->name == NULL) {
+ knot_dname_free(&res);
+ return NULL;
+ }
+
+ dbg_dname_hex((char *)res->name, res->size);
+
+ dbg_dname("Copying %d bytes from the original name.\n",
+ dname->size - size);
+ memcpy(res->name, dname->name, dname->size - size);
+ dbg_dname_hex((char *)res->name, res->size);
+
+ dbg_dname("Copying %d bytes from the suffix.\n", suffix->size);
+ memcpy(res->name + dname->size - size, suffix->name, suffix->size);
+
+ dbg_dname_hex((char *)res->name, res->size);
+
+ knot_dname_find_labels(res, 1);
+
+ return res;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_dname_free(knot_dname_t **dname)
+{
+ if (dname == NULL || *dname == NULL) {
+ return;
+ }
+
+// char *name = knot_dname_to_str((*dname));
+
+// printf("freeing in dname: %s %p\n", name, *dname);
+
+// free(name);
+
+
+ if ((*dname)->name != NULL) {
+ free((*dname)->name);
+ }
+
+ if((*dname)->labels != NULL) {
+ free((*dname)->labels);
+ }
+
+
+// slab_free(*dname);
+ free(*dname);
+ *dname = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2)
+{
+ return knot_dname_cmp(d1, d2, 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2)
+{
+ return knot_dname_cmp(d1, d2, 1);
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2)
+{
+ if (d2->size == 0) {
+ return d1;
+ }
+
+ if (knot_dname_is_fqdn(d1)) {
+ return NULL;
+ }
+
+ // allocate new space
+ uint8_t *new_dname = (uint8_t *)malloc(d1->size + d2->size);
+ CHECK_ALLOC_LOG(new_dname, NULL);
+
+ uint8_t *new_labels = (uint8_t *)malloc(d1->label_count
+ + d2->label_count);
+ if (new_labels == NULL) {
+ ERR_ALLOC_FAILED;
+ free(new_dname);
+ return NULL;
+ }
+
+ dbg_dname("1: copying %d bytes from adress %p to %p\n",
+ d1->size, d1->name, new_dname);
+
+ memcpy(new_dname, d1->name, d1->size);
+
+ dbg_dname("2: copying %d bytes from adress %p to %p\n",
+ d2->size, d2->name, new_dname + d1->size);
+
+ memcpy(new_dname + d1->size, d2->name, d2->size);
+
+ // update labels
+ memcpy(new_labels, d1->labels, d1->label_count);
+ for (int i = 0; i < d2->label_count; ++i) {
+ new_labels[d1->label_count + i] = d2->labels[i] + d1->size;
+ }
+
+ uint8_t *old_labels = d1->labels;
+ d1->labels = new_labels;
+ free(old_labels);
+ d1->label_count += d2->label_count;
+
+ uint8_t *old_name = d1->name;
+ d1->name = new_dname;
+ free(old_name);
+
+ d1->size += d2->size;
+
+ return d1;
+}
+
+void knot_dname_set_id(knot_dname_t *dname, unsigned int id)
+{
+ dname->id = id;
+}
+
+unsigned int knot_dname_get_id(const knot_dname_t *dname)
+{
+ if (dname != NULL) {
+ return dname->id;
+ } else {
+ return 0; /* 0 should never be used and is reserved for err. */
+ }
+}
diff --git a/src/libknot/dname.h b/src/libknot/dname.h
new file mode 100644
index 0000000..c0e3f35
--- /dev/null
+++ b/src/libknot/dname.h
@@ -0,0 +1,428 @@
+/*!
+ * \file dname.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Domain name structure and API for manipulating it.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_DNAME_H_
+#define _KNOT_DNAME_H_
+
+#include <stdint.h>
+#include <string.h>
+#include "common/ref.h"
+
+struct knot_node;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Structure for representing a domain name.
+ *
+ * Stores the domain name in wire format.
+ *
+ * \todo Consider restricting to FQDN only (see knot_dname_new_from_str()).
+ */
+struct knot_dname {
+ ref_t ref; /*!< Reference counting. */
+ uint8_t *name; /*!< Wire format of the domain name. */
+ /*!
+ * \brief Size of the domain name in octets.
+ * \todo Is this needed? Every dname should end with \0 or pointer.
+ */
+ unsigned int size;
+ uint8_t *labels;
+ unsigned short label_count;
+ struct knot_node *node; /*!< Zone node the domain name belongs to. */
+ unsigned int id; /*!< ID of domain name used in zone dumping. */
+};
+
+typedef struct knot_dname knot_dname_t;
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Creates empty dname structure (no name, no owner node).
+ *
+ * \note Newly created dname is referenced, caller is responsible for releasing
+ * it after use.
+ *
+ * \return Newly allocated and initialized dname structure.
+ *
+ * \todo Possibly useless.
+ */
+knot_dname_t *knot_dname_new();
+
+/*!
+ * \brief Creates a dname structure from domain name given in presentation
+ * format.
+ *
+ * The resulting domain name is stored in wire format, but it may not end with
+ * root label (0).
+ *
+ * \note Newly created dname is referenced, caller is responsible for releasing
+ * it after use.
+ *
+ * \param name Domain name in presentation format (labels separated by dots).
+ * \param size Size of the domain name (count of characters with all dots).
+ * \param node Zone node the domain name belongs to. Set to NULL if not
+ * applicable.
+ *
+ * \return Newly allocated and initialized dname structure representing the
+ * given domain name.
+ */
+knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size,
+ struct knot_node *node);
+
+/*!
+ * \brief Creates a dname structure from domain name given in wire format.
+ *
+ * \note The name is copied into the structure.
+ * \note If the given name is not a FQDN, the result will be neither.
+ * \note Newly created dname is referenced, caller is responsible for releasing
+ * it after use.
+ *
+ * \param name Domain name in wire format.
+ * \param size Size of the domain name in octets.
+ * \param node Zone node the domain name belongs to. Set to NULL if not
+ * applicable.
+ *
+ * \return Newly allocated and initialized dname structure representing the
+ * given domain name.
+ *
+ * \todo This function does not check if the given data is in correct wire
+ * format at all. It thus creates a invalid domain name, which if passed
+ * e.g. to knot_dname_to_str() may result in crash. Decide whether it
+ * is OK to retain this and check the data in other functions before
+ * calling this one, or if it should verify the given data.
+ */
+knot_dname_t *knot_dname_new_from_wire(const uint8_t *name,
+ unsigned int size,
+ struct knot_node *node);
+
+knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
+ size_t *pos, size_t size,
+ struct knot_node *node);
+
+/*!
+ * \brief Initializes domain name by the name given in wire format.
+ *
+ * \note The name is copied into the structure.
+ * \note If there is any name in the structure, it will be replaced.
+ * \note If the given name is not a FQDN, the result will be neither.
+ *
+ * \param name Domain name in wire format.
+ * \param size Size of the domain name in octets.
+ * \param node Zone node the domain name belongs to. Set to NULL if not
+ * applicable.
+ * \param target Domain name structure to initialize.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_ENOMEM if allocation of labels info failed.
+ * \retval KNOT_EBADARG if name or target is null.
+ *
+ * \todo This function does not check if the given data is in correct wire
+ * format at all. It thus creates a invalid domain name, which if passed
+ * e.g. to knot_dname_to_str() may result in crash. Decide whether it
+ * is OK to retain this and check the data in other functions before
+ * calling this one, or if it should verify the given data.
+ */
+int knot_dname_from_wire(const uint8_t *name, unsigned int size,
+ struct knot_node *node, knot_dname_t *target);
+
+/*!
+ * \brief Duplicates the given domain name.
+ *
+ * \note Copied dname referense count is reset to 1, caller is responsible
+ * for releasing it after use.
+ *
+ * \param dname Domain name to be copied.
+ *
+ * \return New domain name which is an exact copy of \a dname.
+ */
+knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname);
+
+/*!
+ * \brief Converts the given domain name to string representation.
+ *
+ * \note Allocates new memory, remember to free it.
+ *
+ * \param dname Domain name to be converted.
+ *
+ * \return 0-terminated string representing the given domain name in
+ * presentation format.
+ */
+char *knot_dname_to_str(const knot_dname_t *dname);
+
+int knot_dname_to_lower(knot_dname_t *dname);
+
+int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name,
+ size_t size);
+
+/*!
+ * \brief Returns the domain name in wire format.
+ *
+ * \param dname Domain name.
+ *
+ * \return Wire format of the domain name.
+ */
+const uint8_t *knot_dname_name(const knot_dname_t *dname);
+
+/*!
+ * \brief Returns size of the given domain name.
+ *
+ * \param dname Domain name to get the size of.
+ *
+ * \return Size of the domain name in wire format in octets.
+ */
+unsigned int knot_dname_size(const knot_dname_t *dname);
+
+unsigned int knot_dname_id(const knot_dname_t *dname);
+
+/*!
+ * \brief Returns size of a part of domain name.
+ *
+ * \param dname Domain name.
+ * \param labels Count of labels to get the size of (counted from left).
+ *
+ * \return Size of first \a labels labels of \a dname, counted from left.
+ */
+uint8_t knot_dname_size_part(const knot_dname_t *dname, int labels);
+
+/*!
+ * \brief Returns the zone node the domain name belongs to.
+ *
+ * \param dname Domain name to get the zone node of.
+ *
+ * \return Zone node the domain name belongs to or NULL if none.
+ */
+const struct knot_node *knot_dname_node(const knot_dname_t *dname,
+ int check_version);
+
+struct knot_node *knot_dname_get_node(knot_dname_t *dname,
+ int check_version);
+
+void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node);
+
+void knot_dname_update_node(knot_dname_t *dname);
+
+void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node);
+
+/*!
+ * \brief Checks if the given domain name is a fully-qualified domain name.
+ *
+ * \param dname Domain name to check.
+ *
+ * \retval <> 0 if \a dname is a FQDN.
+ * \retval 0 otherwise.
+ */
+int knot_dname_is_fqdn(const knot_dname_t *dname);
+
+/*!
+ * \brief Creates new domain name by removing leftmost label from \a dname.
+ *
+ * \note Newly created dname reference count is set to 1, caller is responsible
+ * for releasing it after use.
+ *
+ * \param dname Domain name to remove the first label from.
+ *
+ * \return New domain name with the same labels as \a dname, except for the
+ * leftmost label, which is removed.
+ */
+knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname);
+
+/*!
+ * \brief Removes leftmost label from \a dname.
+ *
+ * \param dname Domain name to remove the first label from.
+ */
+void knot_dname_left_chop_no_copy(knot_dname_t *dname);
+
+/*!
+ * \brief Checks if one domain name is a subdomain of other.
+ *
+ * \param sub Domain name to be the possible subdomain.
+ * \param domain Domain name to be the possible parent domain.
+ *
+ * \retval <> 0 if \a sub is a subdomain of \a domain.
+ * \retval 0 otherwise.
+ */
+int knot_dname_is_subdomain(const knot_dname_t *sub,
+ const knot_dname_t *domain);
+
+/*!
+ * \brief Checks if the domain name is a wildcard.
+ *
+ * \param dname Domain name to check.
+ *
+ * \retval <> 0 if \a dname is a wildcard domain name.
+ * \retval 0 otherwise.
+ */
+int knot_dname_is_wildcard(const knot_dname_t *dname);
+
+/*!
+ * \brief Returns the number of labels common for the two domain names (counted
+ * from the rightmost label.
+ *
+ * \param dname1 First domain name.
+ * \param dname2 Second domain name.
+ *
+ * \return Number of labels common for the two domain names.
+ */
+int knot_dname_matched_labels(const knot_dname_t *dname1,
+ const knot_dname_t *dname2);
+
+/*!
+ * \brief Returns the number of labels in the domain name.
+ *
+ * \param dname Domain name to get the label count of.
+ *
+ * \return Number of labels in \a dname.
+ *
+ * \todo Find out if this counts the root label also.
+ */
+int knot_dname_label_count(const knot_dname_t *dname);
+
+/*!
+ * \brief Returns the size of the requested label in the domain name.
+ *
+ * \param dname Domain name to get the label size from.
+ * \param i Index of the label (0 is the leftmost label).
+ *
+ * \return Size of \a i-th label in \a dname (counted from left).
+ */
+uint8_t knot_dname_label_size(const knot_dname_t *dname, int i);
+
+/*!
+ * \brief Replaces the suffix of given size in one domain name with other domain
+ * name.
+ *
+ * \param dname Domain name where to replace the suffix.
+ * \param size Size of the suffix to be replaced.
+ * \param suffix New suffix to be used as a replacement.
+ *
+ * \return New domain name created by replacing suffix of \a dname of size
+ * \a size with \a suffix.
+ */
+knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname,
+ int size,
+ const knot_dname_t *suffix);
+
+/*!
+ * \brief Destroys the given domain name.
+ *
+ * Frees also the data within the struct. This is somewhat different behaviour
+ * than that of RDATA and RRSet structures which do not deallocate their
+ * contents.
+ *
+ * Sets the given pointer to NULL.
+ *
+ * \param dname Domain name to be destroyed.
+ */
+void knot_dname_free(knot_dname_t **dname);
+
+/*!
+ * \brief Compares two domain names (case insensitive).
+ *
+ * \param d1 First domain name.
+ * \param d2 Second domain name.
+ *
+ * \retval < 0 if \a d1 goes before \a d2 in canonical order.
+ * \retval > 0 if \a d1 goes after \a d2 in canonical order.
+ * \retval 0 if the domain names are identical.
+ */
+int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2);
+
+/*!
+ * \brief Compares two domain names (case sensitive).
+ *
+ * \param d1 First domain name.
+ * \param d2 Second domain name.
+ *
+ * \retval < 0 if \a d1 goes before \a d2 in canonical order.
+ * \retval > 0 if \a d1 goes after \a d2 in canonical order.
+ * \retval 0 if the domain names are identical.
+ */
+int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2);
+
+/*!
+ * \brief Concatenates two domain names.
+ *
+ * \note Member \a node is ignored, i.e. preserved.
+ *
+ * \param d1 First domain name (will be modified).
+ * \param d2 Second domain name (will not be modified).
+ *
+ * \return The concatenated domain name (i.e. modified \a d1) or NULL if
+ * the operation is not valid (e.g. \a d1 is a FQDN).
+ */
+knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2);
+
+void knot_dname_set_id(knot_dname_t *dname, unsigned int id);
+
+unsigned int knot_dname_get_id(const knot_dname_t *dname);
+
+/*!
+ * \brief Increment reference counter for dname.
+ *
+ * Function makes shallow copy (reference).
+ *
+ * \param dname Referenced dname.
+ */
+static inline void knot_dname_retain(knot_dname_t *dname) {
+ if (dname) {
+ ref_retain(&dname->ref);
+// char *name = knot_dname_to_str(dname);
+// printf("retain: %s %p %d\n", name, dname, dname->ref.count);
+// free(name);
+
+ }
+}
+
+/*#define knot_dname_retain(d) \
+ knot_dname_retain_((d));\
+ if ((d))\
+ printf("dname_retain: %s() at %s:%d, %p refcount=%zu\n",\
+ __func__, __FILE__, __LINE__, d, (d)->ref.count) */
+
+/*!
+ * \brief Decrement reference counter for dname.
+ *
+ * \param dname Referenced dname.
+ */
+static inline void knot_dname_release(knot_dname_t *dname) {
+ if (dname) {
+// char *name = knot_dname_to_str(dname);
+// printf("releasing: %p %s %d\n", dname, name, dname->ref.count - 1);
+// free(name);
+ ref_release(&dname->ref);
+ }
+}
+
+/*#define knot_dname_release(d) \
+ if ((d))\
+ printf("dname_release: %s() at %s:%d, %p refcount=%zu\n",\
+ __func__, __FILE__, __LINE__, d, (d)->ref.count-1);\
+ knot_dname_release_((d)) */
+
+#endif /* _KNOT_DNAME_H_ */
+
+/*! @} */
diff --git a/src/libknot/edns.c b/src/libknot/edns.c
new file mode 100644
index 0000000..05ebd7b
--- /dev/null
+++ b/src/libknot/edns.c
@@ -0,0 +1,416 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "edns.h"
+#include "common.h"
+#include "util/descriptor.h"
+#include "util/debug.h"
+#include "util/error.h"
+
+/*! \brief Various EDNS constatns. */
+enum knot_edns_consts {
+ /*! \brief Mask for the DO bit. */
+ KNOT_EDNS_DO_MASK = (uint16_t)0x8000,
+ /*! \brief Step for allocation of space for option entries. */
+ KNOT_EDNS_OPTION_STEP = 1
+};
+
+/*! \brief Minimum size of EDNS OPT RR in wire format. */
+static const short KNOT_EDNS_MIN_SIZE = 11;
+
+/*----------------------------------------------------------------------------*/
+
+knot_opt_rr_t *knot_edns_new()
+{
+ knot_opt_rr_t *opt_rr = (knot_opt_rr_t *)malloc(
+ sizeof(knot_opt_rr_t));
+ CHECK_ALLOC_LOG(opt_rr, NULL);
+ opt_rr->size = KNOT_EDNS_MIN_SIZE;
+ opt_rr->option_count = 0;
+ opt_rr->options_max = 0;
+
+ opt_rr->ext_rcode = 0;
+ opt_rr->flags = 0;
+ opt_rr->version = 0;
+
+ return opt_rr;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_edns_new_from_wire(knot_opt_rr_t *opt_rr, const uint8_t *wire,
+ size_t max_size)
+{
+ const uint8_t *pos = wire;
+ int parsed = 0;
+
+ if (pos == NULL || max_size == 0 || opt_rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ if (max_size < KNOT_EDNS_MIN_SIZE) {
+ dbg_edns("Not enough data to parse OPT RR header.\n");
+ return KNOT_EFEWDATA;
+ }
+
+ // owner of EDNS OPT RR must be root (0)
+ if (*pos != 0) {
+ dbg_edns("EDNS packet malformed (expected root "
+ "domain as owner).\n");
+ return KNOT_EMALF;
+ }
+ pos += 1;
+
+ // check the type of the record (must be OPT)
+ if (knot_wire_read_u16(pos) != KNOT_RRTYPE_OPT) {
+ dbg_edns("EDNS packet malformed (expected OPT type"
+ ".\n");
+ return KNOT_EMALF;
+ }
+ pos += 2;
+
+ opt_rr->payload = knot_wire_read_u16(pos);
+ dbg_edns("Parsed payload: %u\n", opt_rr->payload);
+
+ pos += 2;
+ opt_rr->ext_rcode = *(pos++);
+ opt_rr->version = *(pos++);
+ opt_rr->flags = knot_wire_read_u16(pos);
+ pos += 2;
+
+ parsed = KNOT_EDNS_MIN_SIZE;
+
+ // ignore RDATA, but move pos behind them
+ uint16_t rdlength = knot_wire_read_u16(pos);
+ pos += 2;
+
+ if (max_size - parsed < rdlength) {
+ dbg_edns("Not enough data to parse OPT RR.\n");
+ return KNOT_EFEWDATA;
+ }
+
+ while (parsed < rdlength + KNOT_EDNS_MIN_SIZE) {
+ if (max_size - parsed < 4) {
+ dbg_edns("Not enough data to parse OPT RR"
+ " OPTION header.\n");
+ return KNOT_EFEWDATA;
+ }
+ uint16_t code = knot_wire_read_u16(pos);
+ pos += 2;
+ uint16_t length = knot_wire_read_u16(pos);
+ pos += 2;
+ dbg_edns("EDNS OPTION: Code: %u, Length: %u\n",
+ code, length);
+ if (max_size - parsed - 4 < length) {
+ dbg_edns("Not enough data to parse OPT RR"
+ " OPTION data.\n");
+ return KNOT_EFEWDATA;
+ }
+ int ret;
+ if ((ret =
+ knot_edns_add_option(opt_rr, code, length, pos)) != 0) {
+ dbg_edns("Error parsing OPT option field.\n");
+ return ret;
+ }
+ pos += length;
+ parsed += length + 4;
+ }
+
+ return parsed;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr,
+ const knot_rrset_t *rrset)
+{
+ if (opt_rr == NULL || rrset == NULL
+ || knot_rrset_type(rrset) != KNOT_RRTYPE_OPT) {
+ return KNOT_EBADARG;
+ }
+
+ dbg_edns("Parsing payload.\n");
+ opt_rr->payload = knot_rrset_class(rrset);
+
+ // the TTL has switched bytes
+ uint32_t ttl;
+ dbg_edns("TTL: %u\n", knot_rrset_ttl(rrset));
+ knot_wire_write_u32((uint8_t *)&ttl, knot_rrset_ttl(rrset));
+ // first byte of TTL is extended RCODE
+ dbg_edns("TTL: %u\n", ttl);
+ memcpy(&opt_rr->ext_rcode, &ttl, 1);
+ dbg_edns("Parsed extended RCODE: %u.\n", opt_rr->ext_rcode);
+ // second is the version
+ memcpy(&opt_rr->version, (const uint8_t *)(&ttl) + 1, 1);
+ dbg_edns("Parsed version: %u.\n", opt_rr->version);
+ // third and fourth are flags
+ opt_rr->flags = knot_wire_read_u16((const uint8_t *)(&ttl) + 2);
+ dbg_edns("Parsed flags: %u.\n", opt_rr->flags);
+ // size of the header, options are counted elsewhere
+ opt_rr->size = 11;
+
+ int rc = 0;
+ dbg_edns("Parsing options.\n");
+ const knot_rdata_t *rdata = knot_rrset_rdata(rrset);
+
+ // in OPT RR, all RDATA are in one RDATA item stored as BINARY data,
+ // i.e. preceded by their length
+ if (rdata != NULL) {
+ assert(knot_rdata_item_count(rdata) == 1);
+ const uint8_t *raw = (const uint8_t *)
+ knot_rdata_item(rdata, 0)->raw_data;
+ uint16_t size = knot_wire_read_u16(raw);
+ int pos = 2;
+ assert(size > 0);
+ while (pos - 2 < size) {
+ // ensure there is enough data to parse the OPTION CODE
+ // and OPTION LENGTH
+ if (size - pos + 2 < 4) {
+ return KNOT_EMALF;
+ }
+ uint16_t opt_code = knot_wire_read_u16(raw + pos);
+ uint16_t opt_size = knot_wire_read_u16(raw + pos + 2);
+
+ // there should be enough data for parsing the OPTION
+ // data
+ if (size - pos - 2 < opt_size) {
+ return KNOT_EMALF;
+ }
+ rc = knot_edns_add_option(opt_rr, opt_code, opt_size,
+ raw + pos + 4);
+ if (rc != KNOT_EOK) {
+ return rc;
+ }
+ pos += 4 + opt_size;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint16_t knot_edns_get_payload(const knot_opt_rr_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ return opt_rr->payload;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_edns_set_payload(knot_opt_rr_t *opt_rr,
+ uint16_t payload)
+{
+ assert(opt_rr != NULL);
+ opt_rr->payload = payload;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint8_t knot_edns_get_ext_rcode(const knot_opt_rr_t *opt_rr)
+{
+ return opt_rr->ext_rcode;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_edns_set_ext_rcode(knot_opt_rr_t *opt_rr,
+ uint8_t ext_rcode)
+{
+ assert(opt_rr != NULL);
+ opt_rr->ext_rcode = ext_rcode;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint8_t knot_edns_get_version(const knot_opt_rr_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ return opt_rr->version;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_edns_set_version(knot_opt_rr_t *opt_rr,
+ uint8_t version)
+{
+ assert(opt_rr != NULL);
+ opt_rr->version = version;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint16_t knot_edns_get_flags(const knot_opt_rr_t *opt_rr)
+{
+ assert(opt_rr != NULL);
+ return opt_rr->flags;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_edns_do(const knot_opt_rr_t *opt_rr)
+{
+ if (opt_rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ dbg_edns("Flags: %u\n", opt_rr->flags);
+ return (opt_rr->flags & KNOT_EDNS_DO_MASK);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_edns_set_do(knot_opt_rr_t *opt_rr)
+{
+ if (opt_rr == NULL) {
+ return;
+ }
+
+ opt_rr->flags |= KNOT_EDNS_DO_MASK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_edns_add_option(knot_opt_rr_t *opt_rr, uint16_t code,
+ uint16_t length, const uint8_t *data)
+{
+ if (opt_rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ if (opt_rr->option_count == opt_rr->options_max) {
+ knot_opt_option_t *options_new =
+ (knot_opt_option_t *)calloc(
+ (opt_rr->options_max + KNOT_EDNS_OPTION_STEP),
+ sizeof(knot_opt_option_t));
+ CHECK_ALLOC_LOG(options_new, KNOT_ENOMEM);
+ memcpy(options_new, opt_rr->options, opt_rr->option_count);
+ opt_rr->options = options_new;
+ opt_rr->options_max += KNOT_EDNS_OPTION_STEP;
+ }
+
+ dbg_edns("Adding option.\n");
+ dbg_edns("Code: %u.\n", code);
+ dbg_edns("Length: %u.\n", length);
+ dbg_edns("Data: %p.\n", data);
+
+ opt_rr->options[opt_rr->option_count].data = (uint8_t *)malloc(length);
+ CHECK_ALLOC_LOG(opt_rr->options[opt_rr->option_count].data, KNOT_ENOMEM);
+ memcpy(opt_rr->options[opt_rr->option_count].data, data, length);
+
+ opt_rr->options[opt_rr->option_count].code = code;
+ opt_rr->options[opt_rr->option_count].length = length;
+
+ ++opt_rr->option_count;
+ opt_rr->size += 4 + length;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_edns_has_option(const knot_opt_rr_t *opt_rr, uint16_t code)
+{
+ if (opt_rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ int i = 0;
+ while (i < opt_rr->option_count && opt_rr->options[i].code != code) {
+ ++i;
+ }
+
+ assert(i >= opt_rr->option_count || opt_rr->options[i].code == code);
+
+ return (i < opt_rr->option_count);
+}
+
+/*----------------------------------------------------------------------------*/
+
+short knot_edns_to_wire(const knot_opt_rr_t *opt_rr, uint8_t *wire,
+ size_t max_size)
+{
+ if (opt_rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ assert(KNOT_EDNS_MIN_SIZE <= max_size);
+
+ if (max_size < opt_rr->size) {
+ dbg_edns("Not enough place for OPT RR wire format.\n");
+ return KNOT_ESPACE;
+ }
+
+ uint8_t *pos = wire;
+ *(pos++) = 0;
+ knot_wire_write_u16(pos, KNOT_RRTYPE_OPT);
+ pos += 2;
+ knot_wire_write_u16(pos, opt_rr->payload);
+ pos += 2;
+ *(pos++) = opt_rr->ext_rcode;
+ *(pos++) = opt_rr->version;
+ knot_wire_write_u16(pos, opt_rr->flags);
+ pos += 2;
+
+ uint8_t *rdlen = pos;
+ uint16_t len = 0;
+ pos += 2;
+
+ // OPTIONs
+ for (int i = 0; i < opt_rr->option_count; ++i) {
+ knot_wire_write_u16(pos, opt_rr->options[i].code);
+ pos += 2;
+ knot_wire_write_u16(pos, opt_rr->options[i].length);
+ pos += 2;
+ memcpy(pos, opt_rr->options[i].data, opt_rr->options[i].length);
+ pos += opt_rr->options[i].length;
+ len += 4 + opt_rr->options[i].length;
+ }
+
+ knot_wire_write_u16(rdlen, len);
+
+ return opt_rr->size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+short knot_edns_size(knot_opt_rr_t *opt_rr)
+{
+ if (opt_rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return opt_rr->size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_edns_free(knot_opt_rr_t **opt_rr)
+{
+ if (opt_rr == NULL || *opt_rr == NULL) {
+ return;
+ }
+
+ if ((*opt_rr)->option_count > 0) {
+ free((*opt_rr)->options);
+ }
+ free(*opt_rr);
+ *opt_rr = NULL;
+}
diff --git a/src/libknot/edns.h b/src/libknot/edns.h
new file mode 100644
index 0000000..010d155
--- /dev/null
+++ b/src/libknot/edns.h
@@ -0,0 +1,273 @@
+/*!
+ * \file edns.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Functions for manipulating and parsing EDNS OPT pseudo-RR.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_EDNS_H_
+#define _KNOT_EDNS_H_
+
+#include <stdint.h>
+
+#include "util/utils.h"
+#include "rrset.h"
+
+/*----------------------------------------------------------------------------*/
+/*! \brief Structure representing one OPT RR Option. */
+struct knot_opt_option {
+ uint16_t code;
+ uint16_t length;
+ uint8_t *data;
+};
+
+/*! \brief Structure representing one OPT RR Option. */
+typedef struct knot_opt_option knot_opt_option_t;
+
+/*!
+ * \brief Structure for holding EDNS parameters.
+ *
+ * \todo NSID
+ */
+struct knot_opt_rr {
+ uint16_t payload; /*!< UDP payload. */
+ uint8_t ext_rcode; /*!< Extended RCODE. */
+
+ /*!
+ * \brief Supported version of EDNS.
+ *
+ * Set to EDNS_NOT_SUPPORTED if not supported.
+ */
+ uint8_t version;
+
+ uint16_t flags; /*!< EDNS flags. */
+ knot_opt_option_t *options; /*!< EDNS options. */
+ short option_count; /*!< Count of EDNS options in this OPT RR.*/
+ short options_max; /*!< Maximum count of options. */
+ short size; /*!< Total size of the OPT RR in wire format. */
+};
+
+/*! \brief Structure for holding EDNS parameters. */
+typedef struct knot_opt_rr knot_opt_rr_t;
+
+/*----------------------------------------------------------------------------*/
+/*! \brief Constants for supported versions of EDNS. */
+enum knot_edns_versions {
+ EDNS_VERSION_0 = (uint8_t)0, /*!< EDNS version 0. */
+ EDNS_NOT_SUPPORTED = (uint8_t)255 /*!< EDNS not supported. */
+};
+
+/*! \brief Constants for EDNS option codes. */
+enum knot_edns_option_codes {
+ EDNS_OPTION_NSID = (uint16_t)3 /*!< NSID option code. */
+};
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates new empty OPT RR structure for holding EDNS parameters.
+ *
+ * \return New empty knot_opt_rr_t structure, or NULL if not successful.
+ */
+knot_opt_rr_t *knot_edns_new();
+
+/*!
+ * \brief Initializes OPT RR structure from given OPT RR in wire format.
+ *
+ * \param opt_rr OPT RR structure to initialize.
+ * \param wire Wire format of the OPT RR to parse.
+ * \param max_size Maximum size of the wire format in bytes (may be more
+ * than acutal size of the OPT RR).
+ *
+ * \return Size of the parserd OPT RR in bytes if successful (always > 0).
+ * \retval KNOT_EBADARG
+ * \retval KNOT_EFEWDATA
+ * \retval KNOT_EMALF
+ * \retval KNOT_ENOMEM
+ */
+int knot_edns_new_from_wire(knot_opt_rr_t *opt_rr, const uint8_t *wire,
+ size_t max_size);
+
+int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr,
+ const knot_rrset_t *rrset);
+
+/*!
+ * \brief Returns the UDP payload stored in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR structure to get the payload from.
+ *
+ * \return UDP payload in bytes.
+ */
+uint16_t knot_edns_get_payload(const knot_opt_rr_t *opt_rr);
+
+/*!
+ * \brief Sets the UDP payload field in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR structure to set the payload to.
+ * \param payload UDP payload in bytes.
+ */
+void knot_edns_set_payload(knot_opt_rr_t *opt_rr, uint16_t payload);
+
+/*!
+ * \brief Returns the Extended RCODE stored in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR structure to get the Extended RCODE from.
+ *
+ * \return Extended RCODE.
+ */
+uint8_t knot_edns_get_ext_rcode(const knot_opt_rr_t *opt_rr);
+
+/*!
+ * \brief Sets the Extended RCODE field in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR structure to set the Extended RCODE to.
+ * \param ext_rcode Extended RCODE to set.
+ */
+void knot_edns_set_ext_rcode(knot_opt_rr_t *opt_rr, uint8_t ext_rcode);
+
+/*!
+ * \brief Returns the EDNS version stored in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR structure to get the EDNS version from.
+ *
+ * \return EDNS version.
+ */
+uint8_t knot_edns_get_version(const knot_opt_rr_t *opt_rr);
+
+/*!
+ * \brief Sets the EDNS version field in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR structure to set the EDNS version to.
+ * \param version EDNS version to set.
+ */
+void knot_edns_set_version(knot_opt_rr_t *opt_rr, uint8_t version);
+
+/*!
+ * \brief Returns the flags stored in the OPT RR.
+ *
+ * \warning This function does not check the parameter, so ensure to check it
+ * before calling the function. It must not be NULL.
+ * \note There is an assert() for debug checking of the parameter.
+ *
+ * \param opt_rr OPT RR structure to get the flags from.
+ *
+ * \return EDNS flags.
+ */
+uint16_t knot_edns_get_flags(const knot_opt_rr_t *opt_rr);
+
+/*!
+ * \brief Returns the state of the DO bit in the OPT RR flags.
+ *
+ * \param opt_rr OPT RR structure to get the DO bit from.
+ *
+ * \return <> 0 if the DO bit is set.
+ * \return 0 if the DO bit is not set.
+ */
+int knot_edns_do(const knot_opt_rr_t *opt_rr);
+
+/*!
+ * \brief Sets the DO bit in the OPT RR.
+ *
+ * \param opt_rr OPT RR structure to set the DO bit in.
+ */
+void knot_edns_set_do(knot_opt_rr_t *opt_rr);
+
+/*!
+ * \brief Adds EDNS Option to the OPT RR.
+ *
+ * \param opt_rr OPT RR structure to add the Option to.
+ * \param code Option code.
+ * \param length Option data length in bytes.
+ * \param data Option data.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+int knot_edns_add_option(knot_opt_rr_t *opt_rr, uint16_t code,
+ uint16_t length, const uint8_t *data);
+
+/*!
+ * \brief Checks if the OPT RR contains Option with the specified code.
+ *
+ * \param opt_rr OPT RR structure to check for the Option in.
+ * \param code Option code to check for.
+ *
+ * \retval <> 0 if the OPT RR contains Option with Option code \a code.
+ * \retval 0 otherwise.
+ */
+int knot_edns_has_option(const knot_opt_rr_t *opt_rr, uint16_t code);
+
+/*!
+ * \brief Converts the given OPT RR into wire format.
+ *
+ * \param opt_rr OPT RR structure to convert into wire format.
+ * \param wire Place to put the wire format to.
+ * \param max_size Maximum space available for the wire format in bytes.
+ *
+ * \return Size of the wire format in bytes if successful.
+ * \retval KNOT_ESPACE
+ */
+short knot_edns_to_wire(const knot_opt_rr_t *opt_rr, uint8_t *wire,
+ size_t max_size);
+
+/*!
+ * \brief Returns size of the OPT RR in wire format.
+ *
+ * \param opt_rr OPT RR to get the size of.
+ *
+ * \return Size of the OPT RR in bytes.
+ */
+short knot_edns_size(knot_opt_rr_t *opt_rr);
+
+/*!
+ * \brief Properly destroys the OPT RR structure.
+ *
+ * \note Also sets the given pointer to NULL.
+ */
+void knot_edns_free(knot_opt_rr_t **opt_rr);
+
+#endif /* _KNOT_EDNS_H_ */
+
+/*! @} */
diff --git a/src/libknot/hash/cuckoo-hash-table.c b/src/libknot/hash/cuckoo-hash-table.c
new file mode 100644
index 0000000..c5d1c4f
--- /dev/null
+++ b/src/libknot/hash/cuckoo-hash-table.c
@@ -0,0 +1,1688 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h> /* defines uint32_t etc */
+#include <assert.h>
+#include <pthread.h>
+#include <math.h>
+
+#include <urcu.h>
+
+#include "util/utils.h"
+#include "common.h"
+#include "util/debug.h"
+#include "hash/cuckoo-hash-table.h"
+#include "hash/hash-functions.h"
+#include "common/dynamic-array.h"
+
+/*----------------------------------------------------------------------------*/
+/* Macros and inline functions */
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Default size table holding information about used hash table cells
+ * when hashing.
+ */
+#define RELOCATIONS_DEFAULT 200
+
+/*!
+ * \brief Maximum size table holding information about used hash table cells
+ * when hashing (just for debug issues).
+ */
+#define RELOCATIONS_MAX 1000
+
+/*!
+ * \brief Macro for hashing the given key using the universal system.
+ *
+ * \param system Universal system to use for the hashing.
+ * \param key Key to hash.
+ * \param length Size of the key in bytes.
+ * \param exp Exponent of the hash table size (the size is a power of 2).
+ * \param table Hash table index.
+ * \param gen Universal system generation.
+ *
+ * \return Hashed key.
+ */
+#define HASH(system, key, length, exp, gen, table) \
+ us_hash(system, fnv_32_buf(key, length, FNV1_32_INIT), exp, table, gen)
+
+/*!
+ * \brief Approximate ratio of hash table size to number of hashed items when 2
+ * tables are used.
+ */
+static const float SIZE_RATIO_2 = 2;
+
+/*!
+ * \brief Approximate ratio of hash table size to number of hashed items when 3
+ * tables are used.
+ */
+static const float SIZE_RATIO_3 = 1.15;
+
+/*!
+ * \brief Approximate ratio of hash table size to number of hashed items when 4
+ * tables are used.
+ */
+static const float SIZE_RATIO_4 = 1.08;
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Flag marking the generation of hash table or its item to be 1. */
+static const uint8_t FLAG_GENERATION1 = 0x1; // 00000001
+/*! \brief Flag marking the generation of hash table or its item to be 2. */
+static const uint8_t FLAG_GENERATION2 = 0x2; // 00000010
+/*! \brief Flag marking both generations. */
+static const uint8_t FLAG_GENERATION_BOTH = 0x3; // 00000011
+
+/*! \brief Flag used to mark the table when it's being rehashed. */
+static const uint8_t FLAG_REHASH = 0x4; // 00000100
+
+/*----------------------------------------------------------------------------*/
+/*! \brief Clears the table / item flags. */
+static inline void CLEAR_FLAGS(uint8_t *flags)
+{
+ *flags = (uint8_t)0x0;
+}
+
+/*! \brief Returns the generation stored in the flags. */
+static inline uint8_t GET_GENERATION(uint8_t flags)
+{
+ return (flags & FLAG_GENERATION_BOTH);
+}
+
+/*! \brief Checks if the generation stored in both flags are the same. */
+static inline int EQUAL_GENERATIONS(uint8_t flags1, uint8_t flags2)
+{
+ return (GET_GENERATION(flags1) == GET_GENERATION(flags2));
+}
+
+/*! \brief Checks if the generation stored in the flags is 1. */
+static inline int IS_GENERATION1(uint8_t flags)
+{
+ return ((flags & FLAG_GENERATION1) != 0);
+}
+
+/*! \brief Sets the generation stored in the flags to 1. */
+static inline void SET_GENERATION1(uint8_t *flags)
+{
+ *flags = ((*flags) & ~FLAG_GENERATION2) | FLAG_GENERATION1;
+}
+
+/*! \brief Checks if the generation stored in the flags is 2. */
+static inline int IS_GENERATION2(uint8_t flags)
+{
+ return ((flags & FLAG_GENERATION2) != 0);
+}
+
+/*! \brief Sets the generation stored in the flags to 2. */
+static inline void SET_GENERATION2(uint8_t *flags)
+{
+ *flags = ((*flags) & ~FLAG_GENERATION1) | FLAG_GENERATION2;
+}
+
+/*! \brief Sets the generation stored in the flags to the given generation. */
+static inline void SET_GENERATION(uint8_t *flags, uint8_t generation)
+{
+ *flags = ((*flags) & ~FLAG_GENERATION_BOTH) | generation;
+}
+
+/*! \brief Sets the generation stored in the flags to the next one (cyclic). */
+static inline uint8_t SET_NEXT_GENERATION(uint8_t *flags)
+{
+ return ((*flags) ^= FLAG_GENERATION_BOTH);
+}
+
+/*! \brief Returns the next generation to the one stored in flags (cyclic). */
+static inline uint8_t NEXT_GENERATION(uint8_t flags)
+{
+ return ((flags & FLAG_GENERATION_BOTH) ^ FLAG_GENERATION_BOTH);
+}
+
+/*! \brief Sets the rehashing flag to the flags. */
+static inline void SET_REHASHING_ON(uint8_t *flags)
+{
+ *flags = (*flags | FLAG_REHASH);
+}
+
+/*! \brief Removes the rehashing flag from the flags. */
+static inline void SET_REHASHING_OFF(uint8_t *flags)
+{
+ *flags = (*flags & ~FLAG_REHASH);
+}
+
+/*! \brief Checks if the rehashing flag is set in the flags. */
+static inline int IS_REHASHING(uint8_t flags)
+{
+ return ((flags & FLAG_REHASH) != 0);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Private functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Returns the exponent of the nearest larger power of two.
+ */
+static uint get_larger_exp(uint n)
+{
+ uint res = 0;
+ while (hashsize(++res) < n) {}
+
+ return res;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Counts the ideal table count and the exponent of those tables' sizes.
+ *
+ * Only 3 or 4 hash tables are considered. The setup in which less items are
+ * wasted is recommended.
+ *
+ * \param items Number of items to hash.
+ * \param table_count Recommended number of tables will be saved here.
+ *
+ * \return Exponent of the tables' sizes.
+ */
+static uint get_table_exp_and_count(uint items, uint *table_count)
+{
+ // considering only 3 or 4 tables
+ int exp3 = get_larger_exp((items * SIZE_RATIO_3) / 3);
+ int exp4 = get_larger_exp(items * SIZE_RATIO_4) - 2;
+
+ if (exp4 < 0) {
+ exp4 = 1;
+ }
+
+ dbg_ck("Determining ideal table size...\n");
+ dbg_ck("\tNumber of items: %u\n", items);
+ dbg_ck("\tThree tables: size of one table: %u, total size: %u\n",
+ hashsize(exp3), 3 * hashsize(exp3));
+ dbg_ck("\tFour tables: size of one table: %u, total size: %u\n",
+ hashsize(exp4), 4 * hashsize(exp4));
+
+ // we need exponent at least 1 (this is quite ugly..)
+ if (exp3 == 0) {
+ exp3 = 1;
+ }
+ if (exp4 == 0) {
+ exp4 = 1;
+ }
+
+ if (exp3 >= 32 || exp4 >= 32) {
+ return 0;
+ }
+
+ if (((hashsize(exp3) * 3) - (items)) < ((hashsize(exp4) * 4) - items)) {
+ *table_count = 3;
+ return exp3;
+ } else {
+ *table_count = 4;
+ return exp4;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Counts the maximum effective item count based on size of the tables.
+ *
+ * For 3 tables, the effective utilization should be around 91%.
+ * For 4 tables it is 97%.
+ *
+ * See Fotakis, Dimitris, et al. - Space Efficient Hash Tables with Worst Case
+ * Constant Access Time. CiteSeerX. 2003
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.14.5337
+ */
+static uint get_max_table_items(uint table_count, int table_exponent)
+{
+ assert(table_count == 3 || table_count == 4);
+
+ float coef;
+
+ if (table_count == 3) {
+ coef = 0.91;
+ } else {
+ coef = 0.97;
+ }
+
+ return (uint)floor((table_count * hashsize(table_exponent)) * coef);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ck_is_full(const ck_hash_table_t *table)
+{
+ return (table->items >= get_max_table_items(table->table_count,
+ table->table_size_exp));
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ck_stash_is_full(const ck_hash_table_t *table)
+{
+ return (table->items_in_stash >= STASH_SIZE_MAX);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Clears the given item by assigning a NULL pointer to it.
+ */
+static inline void ck_clear_item(ck_hash_table_item_t **item)
+{
+ *item = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Insert given contents to the hash table item.
+ */
+static void ck_fill_item(const char *key, size_t key_length, void *value,
+ uint generation, ck_hash_table_item_t *item)
+{
+ // must allocate new space for key and value, otherwise it will be lost!
+ item->key = key;
+ item->key_length = key_length;
+ item->value = value;
+ CLEAR_FLAGS(&item->timestamp);
+ item->timestamp = generation;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Swaps two hash table items.
+ */
+static inline void ck_swap_items(ck_hash_table_item_t **item1,
+ ck_hash_table_item_t **item2)
+{
+ ck_hash_table_item_t *tmp = *item1;
+ *item1 = *item2;
+ *item2 = tmp;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Sets the \a item pointer to the \a to pointer.
+ */
+static inline void ck_put_item(ck_hash_table_item_t **to,
+ ck_hash_table_item_t *item)
+{
+ *to = item;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Checks if the hash was already used twice.
+ *
+ * If yes, it means we entered a loop in the hashing process, so we must stop.
+ * Otherwise it remembers that we used the hash.
+ *
+ * \note According to Kirsch, et al. a check that at most one hash was used
+ * twice should be sufficient. We will retain our version for now.
+ *
+ * \param used Array of used table indices (hashes).
+ * \param hash Hash to check.
+ *
+ * \retval -1 if the hash was already used twice.
+ * \retval -2 if an error occured.
+ * \retval 0 if the hash was not used twice yet.
+ */
+static uint ck_check_used_twice(da_array_t *used, uint32_t hash)
+{
+ uint i = 0, found = 0;
+ while (i <= da_get_count(used) && found < 2) {
+ ++i;
+ if (((uint *)(da_get_items(used)))[i] == hash) {
+ ++found;
+ }
+ }
+
+ if (i <= da_get_count(used) && found == 2) {
+ dbg_ck_hash("Hashing entered infinite loop.\n");
+ return -1;
+ } else {
+ if (da_reserve(used, 1) < 0) {
+ ERR_ALLOC_FAILED;
+ return -2;
+ }
+ ((uint *)da_get_items(used))[da_get_count(used)] = hash;
+ da_occupy(used, 1);
+ assert(da_get_count(used) < RELOCATIONS_MAX);
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Compares the key of item with the given key.
+ *
+ * \param item Item to compare with.
+ * \param key Key to compare.
+ * \param length Size of the key in bytes.
+ *
+ * \return <> 0 if the keys match.
+ * \return 0 if they don't.
+ */
+static inline uint ck_items_match(const ck_hash_table_item_t *item,
+ const char *key, size_t length)
+{
+ return (length == item->key_length
+ && (strncmp(item->key, key, length) == 0));
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Switches the given table number to a randomly chosen other table
+ * number.
+ */
+static inline void ck_next_table(uint *table, uint table_count)
+{
+ uint next;
+ while ((*table) == (next = knot_quick_rand() % table_count)) {}
+ *table = next;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tries to find the given key in the hash table's stash.
+ *
+ * \param table Hash table to search in.
+ * \param key Key to find.
+ * \param length Size of the key in bytes.
+ *
+ * \return Hash table item matching the key or NULL if not found in the stash.
+ */
+static ck_hash_table_item_t **ck_find_in_stash(const ck_hash_table_t *table,
+ const char *key, uint length)
+{
+ ck_stash_item_t *item = table->stash;
+ while (item != NULL) {
+ dbg_ck("Comparing item in stash (key: %.*s (size %zu))"
+ "with searched item (key %.*s (size %u)).\n",
+ (int)item->item->key_length, item->item->key,
+ item->item->key_length, (int)length, key, length);
+ if (ck_items_match(item->item, key, length)) {
+ return &item->item;
+ }
+ item = item->next;
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tries to find item with given key using hash functions from the given
+ * generation.
+ *
+ * \param table Hash table to search in.
+ * \param key Key to find.
+ * \param length Size of the key in bytes.
+ * \param generation Generation of items (table) to use. Items having other
+ * generation are ignored.
+ */
+static ck_hash_table_item_t **ck_find_gen(const ck_hash_table_t *table,
+ const char *key,
+ size_t length, uint8_t generation)
+{
+ uint32_t hash;
+ dbg_ck("Finding item in generation: %u\n", generation);
+
+ // check hash tables
+ for (uint t = 0; t < table->table_count; ++t) {
+ hash = HASH(&table->hash_system, key, length,
+ table->table_size_exp, generation, t);
+
+ dbg_ck("Hash: %u, key: %.*s\n", hash, (int)length, key);
+ dbg_ck("Table %d, hash: %u, item: %p\n", t + 1, hash,
+ table->tables[t][hash]);
+ if (table->tables[t][hash] != NULL) {
+ dbg_ck("Table %u, key: %.*s, value: %p, key "
+ "length: %zu\n",
+ t + 1, (int)table->tables[t][hash]->key_length,
+ table->tables[t][hash]->key,
+ table->tables[t][hash]->value,
+ table->tables[t][hash]->key_length);
+ }
+
+ if (table->tables[t][hash] &&
+ ck_items_match(table->tables[t][hash], key, length)) {
+ // found
+ return &table->tables[t][hash];
+ }
+ }
+
+ // try to find in stash
+ dbg_ck("Searching in stash...\n");
+
+ ck_hash_table_item_t **found =
+ ck_find_in_stash(table, key, length);
+
+ dbg_ck("Found pointer: %p\n", found);
+ if (found != NULL) {
+ dbg_ck("Stash, key: %.*s, value: %p, key length: %zu\n",
+ (int)(*found)->key_length, (*found)->key,
+ (*found)->value, (*found)->key_length);
+ }
+
+ // ck_find_in_buffer returns NULL if not found, otherwise pointer to
+ // item
+ return found;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Finds item with given key and returns non-constant pointer to pointer
+ * to the appropriate hash table item.
+ *
+ * \param table Hash table to search in.
+ * \param key Key to find.
+ * \param length Size of the key in bytes.
+ */
+static ck_hash_table_item_t **ck_find_item_nc(const ck_hash_table_t *table,
+ const char *key, size_t length)
+{
+ // get the generation of the table so that we use the same value
+ uint8_t generation = table->generation;
+
+ // find item using the table generation's hash functions
+ ck_hash_table_item_t **found = ck_find_gen(table, key, length,
+ GET_GENERATION(generation));
+ // if rehashing is in progress, try the next generation's functions
+ if (!found && IS_REHASHING(generation)) {
+ found = ck_find_gen(table, key, length,
+ NEXT_GENERATION(generation));
+ }
+
+ return found;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Hashes the given item using the given generation.
+ *
+ * \param table Hash table where to put the item.
+ * \param to_hash In: Item to hash. Out: NULL if successful, item that failed
+ * to hash if not.
+ * \param free Free place where to put the last moved item when the hasing
+ * is unsuccessful.
+ * \param generation Generation of items (table) to be used for hashing.
+ *
+ * \retval 0 if successful and no loop occured.
+ * \retval 1 if a loop occured and the item was inserted to the \a free place.
+ */
+static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash,
+ ck_hash_table_item_t **free, uint8_t generation)
+{
+ da_array_t used[table->table_count];
+ for (uint i = 0; i < table->table_count; ++i) {
+ da_initialize(&used[i], RELOCATIONS_DEFAULT, sizeof(uint));
+ }
+
+ // hash until empty cell is encountered or until loop appears
+
+ dbg_ck_hash("Hashing key: %.*s of size %zu.\n",
+ (int)(*to_hash)->key_length, (*to_hash)->key,
+ (*to_hash)->key_length);
+
+ uint next_table = 0;
+
+ uint32_t hash = HASH(&table->hash_system, (*to_hash)->key,
+ (*to_hash)->key_length, table->table_size_exp,
+ generation, next_table);
+
+ dbg_ck_hash("New hash: %u.\n", hash);
+ assert(hash < hashsize(table->table_size_exp));
+
+ ((uint *)da_get_items(&used[next_table]))
+ [da_get_count(&used[next_table])] = hash;
+ ck_hash_table_item_t **next = &table->tables[next_table][hash];
+ dbg_ck_hash("Item to be moved: %p, place in table: %p\n",
+ *next, next);
+ ck_hash_table_item_t **moving = to_hash;
+
+ int loop = 0;
+
+ while (*next != NULL) {
+ dbg_ck_hash("Swapping items to hash: %p and Moving: %p\n",
+ to_hash, moving);
+ ck_swap_items(to_hash, moving); // first time it's unnecessary
+
+ // set the generation of the inserted item to the next
+ SET_GENERATION(&(*moving)->timestamp, generation);
+
+ moving = next;
+
+ dbg_ck_hash("Moving item from table %u, key: %.*s, hash %u ",
+ next_table + 1, (int)(*moving)->key_length,
+ (*moving)->key, hash);
+
+ // if rehashing and the 'next' item is from the old generation,
+ // start from table 1
+ if (generation != table->generation &&
+ EQUAL_GENERATIONS((*next)->timestamp, table->generation)) {
+ next_table = 0;
+ } else {
+ ck_next_table(&next_table, table->table_count);
+ }
+
+ hash = HASH(&table->hash_system, (*next)->key,
+ (*next)->key_length, table->table_size_exp,
+ generation, next_table);
+
+ next = &table->tables[next_table][hash];
+
+ dbg_ck_hash("to table %u, hash %u, item: %p, place: %p\n",
+ next_table + 1, hash, *next, next);
+
+ if ((*next) != NULL) {
+ dbg_ck_hash("Table %u, hash: %u, key: %.*s\n",
+ next_table + 1, hash,
+ (int)(*next)->key_length, (*next)->key);
+ }
+
+ // check if this cell wasn't already used in this item's hashing
+ if (ck_check_used_twice(&used[next_table], hash) != 0) {
+ next = free;
+ loop = -1;
+ break;
+ }
+ }
+
+ dbg_ck_hash("Putting pointer %p (*moving) to item %p (next).\n",
+ *moving, next);
+
+ ck_put_item(next, *moving);
+ // set the new generation for the inserted item
+ SET_GENERATION(&(*next)->timestamp, generation);
+ dbg_ck_hash("Putting pointer %p (*old) to item %p (moving).\n",
+ *to_hash, moving);
+
+ ck_put_item(moving, *to_hash);
+
+ // set the new generation for the inserted item
+ SET_GENERATION(&(*moving)->timestamp, generation);
+ *to_hash = NULL;
+
+ for (uint i = 0; i < table->table_count; ++i) {
+ da_destroy(&used[i]);
+ }
+
+ return loop;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void ck_rollback_rehash(ck_hash_table_t *table)
+{
+ // set old generation in tables
+ for (int i = 0; i < hashsize(table->table_size_exp); ++i) {
+ // no need for locking - timestamp is not used in lookup
+ // and two paralel insertions (and thus rehashings) are
+ // impossible
+ for (uint t = 0; t < table->table_count; ++t) {
+ if (table->tables[t][i] != NULL) {
+ SET_GENERATION(&table->tables[t][i]->timestamp,
+ table->generation);
+ }
+ }
+ }
+
+ // set old generation in stash
+ ck_stash_item_t *item = table->stash;
+ while (item != NULL) {
+ assert(item->item != NULL);
+ SET_GENERATION(&item->item->timestamp, table->generation);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adds the given item to the hash table's stash.
+ *
+ * \param table Hash table to add the item to.
+ * \param item Item to add.
+ *
+ * \retval 0 if successful.
+ * \retval -1 if an error occured.
+ */
+int ck_add_to_stash(ck_hash_table_t *table, ck_hash_table_item_t *item)
+{
+ ck_stash_item_t *new_item
+ = (ck_stash_item_t *)malloc(sizeof(ck_stash_item_t));
+ if (new_item == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ new_item->item = item;
+ new_item->next = table->stash;
+ table->stash = new_item;
+
+ dbg_ck_hash("First item in stash (now inserted): key: %.*s (size %zu)"
+ ", value: %p\n", (int)table->stash->item->key_length,
+ table->stash->item->key, table->stash->item->key_length,
+ table->stash->item->value);
+
+ // increase count of items in stash
+ ++table->items_in_stash;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ck_new_table(ck_hash_table_item_t ***table, int exp)
+{
+ *table = (ck_hash_table_item_t **)
+ malloc(hashsize(exp) * sizeof(ck_hash_table_item_t *));
+ if (*table == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ // set to 0
+ memset(*table, 0, hashsize(exp) * sizeof(ck_hash_table_item_t *));
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Public functions */
+/*----------------------------------------------------------------------------*/
+
+ck_hash_table_t *ck_create_table(uint items)
+{
+ ck_hash_table_t *table =
+ (ck_hash_table_t *)malloc(sizeof(ck_hash_table_t));
+
+ if (table == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ memset(table, 0, sizeof(ck_hash_table_t));
+
+ // determine ideal size of one table in powers of 2 and save the
+ // exponent
+ table->table_size_exp = get_table_exp_and_count(items,
+ &table->table_count);
+ assert(table->table_size_exp <= 32);
+
+ if (table->table_size_exp == 0) {
+ dbg_ck("Failed to count exponent of the hash table.\n");
+ return NULL;
+ }
+
+ dbg_ck("Creating hash table for %u items.\n", items);
+ dbg_ck("Exponent: %u, number of tables: %u\n ",
+ table->table_size_exp, table->table_count);
+ dbg_ck("Table size: %u items, each %zu bytes, total %zu bytes\n",
+ hashsize(table->table_size_exp),
+ sizeof(ck_hash_table_item_t *),
+ hashsize(table->table_size_exp)
+ * sizeof(ck_hash_table_item_t *));
+
+ // create tables
+ for (uint t = 0; t < table->table_count; ++t) {
+ dbg_ck("Creating table %u...\n", t);
+ if (ck_new_table(&table->tables[t], table->table_size_exp)
+ != 0) {
+ for (uint i = 0; i < t; ++i) {
+ free(table->tables[i]);
+ }
+ free(table);
+ return NULL;
+ }
+ }
+
+ assert(table->stash == NULL);
+ assert(table->hashed == NULL);
+ assert(table->items == 0);
+ assert(table->items_in_stash == 0);
+ assert(table->table_count == MAX_TABLES
+ || table->tables[table->table_count] == NULL);
+
+ // initialize rehash/insert mutex
+ pthread_mutex_init(&table->mtx_table, NULL);
+
+ // set the generation to 1 and initialize the universal system
+ CLEAR_FLAGS(&table->generation);
+ SET_GENERATION1(&table->generation);
+
+ us_initialize(&table->hash_system);
+
+ return table;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void ck_destroy_table(ck_hash_table_t **table, void (*dtor_value)(void *value),
+ int delete_key)
+{
+ assert(table);
+ assert(*table);
+ pthread_mutex_lock(&(*table)->mtx_table);
+
+ // destroy items in tables
+ for (uint i = 0; i < hashsize((*table)->table_size_exp); ++i) {
+ for (uint t = 0; t < (*table)->table_count; ++t) {
+ if ((*table)->tables[t][i] != NULL) {
+ if (dtor_value) {
+ dtor_value(
+ (*table)->tables[t][i]->value);
+ }
+ if (delete_key != 0) {
+ free(
+ (void *)(*table)->tables[t][i]->key);
+ }
+ free((void *)(*table)->tables[t][i]);
+ }
+ }
+ }
+
+ // destroy items in stash
+// ck_hash_table_item_t **stash =
+// ((ck_hash_table_item_t **)(da_get_items(&(*table)->stash)));
+// for (uint i = 0; i < da_get_count(&(*table)->stash); ++i) {
+// assert(stash[i] != NULL);
+// if (dtor_value) {
+// dtor_value(stash[i]->value);
+// }
+// if (delete_key != 0) {
+// free((void *)stash[i]->key);
+// }
+// free((void *)stash[i]);
+// }
+ ck_stash_item_t *item = (*table)->stash;
+ while (item != NULL) {
+ // disconnect the item
+ (*table)->stash = item->next;
+ /*! \todo Investigate this. */
+ assert(item->item != NULL);
+
+ if (dtor_value) {
+ dtor_value(item->item->value);
+ }
+ if (delete_key) {
+ free((void *)item->item->key);
+ }
+
+ free((void *)item->item);
+ free(item);
+ item = (*table)->stash;
+ }
+
+ // deallocate tables
+ for (uint t = 0; t < (*table)->table_count; ++t) {
+ free((*table)->tables[t]);
+ }
+ // destroy stash
+// da_destroy(&(*table)->stash);
+
+ pthread_mutex_unlock(&(*table)->mtx_table);
+ // destroy mutex, assuming that here noone will lock the mutex again
+ pthread_mutex_destroy(&(*table)->mtx_table);
+
+ free(*table);
+ (*table) = NULL;
+}
+
+void ck_table_free(ck_hash_table_t **table)
+{
+ if (table == NULL || *table == NULL) {
+ return;
+ }
+
+ pthread_mutex_lock(&(*table)->mtx_table);
+
+ ck_stash_item_t *item = (*table)->stash;
+ while (item != NULL) {
+ // disconnect the item
+ (*table)->stash = item->next;
+ free(item);
+ item = (*table)->stash;
+ }
+
+ // deallocate tables
+ for (uint t = 0; t < (*table)->table_count; ++t) {
+ free((*table)->tables[t]);
+ }
+
+ pthread_mutex_unlock(&(*table)->mtx_table);
+ pthread_mutex_destroy(&(*table)->mtx_table);
+
+ free(*table);
+ (*table) = NULL;
+}
+
+int ck_resize_table(ck_hash_table_t *table)
+{
+ dbg_ck("Resizing hash table.\n");
+
+ /*
+ * Easiest is just to increment the exponent, resulting in doubling
+ * the table sizes. This is not very memory-effective, but should do
+ * the job.
+ */
+
+ if (table->table_size_exp == 31) {
+ dbg_ck("Hash tables achieved max size (exponent 31).\n");
+ return -1;
+ }
+
+ ck_hash_table_item_t **tables_new[MAX_TABLES];
+ ck_hash_table_item_t **tables_old[MAX_TABLES];
+ int exp_new = table->table_size_exp + 1;
+
+ dbg_ck("New tables exponent: %d\n", exp_new);
+
+ for (int t = 0; t < table->table_count; ++t) {
+ if (ck_new_table(&tables_new[t], exp_new) != 0) {
+ dbg_ck("Failed to create new table.\n");
+ for (int i = 0; i < t; ++i) {
+ free(tables_new[i]);
+ }
+ return -1;
+ }
+ }
+
+ dbg_ck("Created new tables, copying data to them.\n");
+
+ for (int t = 0; t < table->table_count; ++t) {
+ size_t old_size = hashsize(table->table_size_exp)
+ * sizeof(ck_hash_table_item_t *);
+
+ // copy the old table items
+ dbg_ck("Copying to: %p, from %p, size: %zu\n",
+ tables_new[t], table->tables[t], old_size);
+ memcpy(tables_new[t], table->tables[t], old_size);
+ // set the rest to 0
+ dbg_ck("Setting to 0 from %p, size %zu\n",
+ tables_new[t] + hashsize(table->table_size_exp),
+ (hashsize(exp_new) * sizeof(ck_hash_table_item_t *))
+ - old_size);
+ memset(tables_new[t] + hashsize(table->table_size_exp), 0,
+ (hashsize(exp_new) * sizeof(ck_hash_table_item_t *))
+ - old_size);
+ }
+
+ dbg_ck("Done, switching the tables and running rehash.\n");
+
+
+ memcpy(tables_old, table->tables,
+ MAX_TABLES * sizeof(ck_hash_table_item_t **));
+ memcpy(table->tables, tables_new,
+ MAX_TABLES * sizeof(ck_hash_table_item_t **));
+
+ table->table_size_exp = exp_new;
+
+ // delete the old tables
+ for (int t = 0; t < table->table_count; ++t) {
+ free(tables_old[t]);
+ }
+
+ return ck_rehash(table);
+ //return 0;
+}
+
+int ck_insert_item(ck_hash_table_t *table, const char *key,
+ size_t length, void *value)
+{
+ // lock mutex to avoid write conflicts
+ pthread_mutex_lock(&table->mtx_table);
+
+ assert(value != NULL);
+
+ dbg_ck_hash("Inserting item with key: %.*s.\n", (int)length, key);
+ dbg_ck_hash_hex(key, length);
+ dbg_ck_hash("\n");
+
+ // create item structure and fill in the given data, key won't be copied
+ ck_hash_table_item_t *new_item =
+ (ck_hash_table_item_t *)malloc((sizeof(ck_hash_table_item_t)));
+ ck_fill_item(key, length, value, GET_GENERATION(table->generation),
+ new_item);
+
+ // check if the table is not full; if yes, resize and rehash!
+ if (ck_is_full(table)) {
+ dbg_ck("Table is full, resize needed.\n");
+ if (ck_resize_table(table) != 0) {
+ dbg_ck("Failed to resize hash table!\n");
+ return -1;
+ }
+ }
+
+ // there should be at least 2 free places
+ //assert(da_try_reserve(&table->stash, 2) == 0);
+ //da_reserve(&table->stash, 1);
+ ck_hash_table_item_t *free_place = NULL;
+ if (ck_hash_item(table, &new_item, &free_place,
+ table->generation) != 0) {
+
+ dbg_ck("Adding item with key %.*s to stash.\n",
+ (int)free_place->key_length, free_place->key);
+
+ // maybe some limit on the stash and rehash if full
+ if (ck_add_to_stash(table, free_place) != 0) {
+ dbg_ck_hash("Could not add item to stash!!\n");
+ assert(0);
+ }
+
+ if (ck_stash_is_full(table)) {
+ dbg_ck("Stash is full, resize needed.\n");
+ if (ck_resize_table(table) != 0) {
+ dbg_ck("Failed to resize hash table!\n");
+ return -1;
+ }
+ }
+ }
+
+ ++table->items;
+ pthread_mutex_unlock(&table->mtx_table);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const ck_hash_table_item_t *ck_find_item(const ck_hash_table_t *table,
+ const char *key, size_t length)
+{
+ dbg_ck("ck_find_item(), key: %.*s, size: %zu\n",
+ (int)length, key, length);
+
+ ck_hash_table_item_t **found = ck_find_item_nc(table, key, length);
+
+ return (found == NULL) ? NULL : rcu_dereference(*found);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int ck_update_item(const ck_hash_table_t *table, const char *key, size_t length,
+ void *new_value, void (*dtor_value)(void *value))
+{
+ rcu_read_lock(); // is needed?
+
+ assert(new_value != NULL);
+
+ ck_hash_table_item_t **item = ck_find_item_nc(table, key, length);
+
+ if (item == NULL || (*item) == NULL) {
+ return -1;
+ }
+
+ void *old = rcu_xchg_pointer(&(*item)->value, new_value);
+ rcu_read_unlock();
+
+ synchronize_rcu();
+ if (dtor_value) {
+ dtor_value(old);
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int ck_delete_item(const ck_hash_table_t *table, const char *key, size_t length,
+ void (*dtor_value)(void *value), int delete_key)
+{
+ rcu_read_lock(); // is needed?
+ ck_hash_table_item_t **place = ck_find_item_nc(table, key, length);
+
+ if (place == NULL) {
+ return -1;
+ }
+
+ ck_hash_table_item_t *item = *place;
+
+ assert(item != NULL);
+
+ ck_put_item(place, NULL);
+ rcu_read_unlock();
+
+ synchronize_rcu();
+ if (dtor_value) {
+ dtor_value(item->value);
+ }
+ item->value = NULL;
+ if (delete_key != 0) {
+ free((void *)item->key);
+ }
+ free(item);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+ck_hash_table_item_t *ck_remove_item(ck_hash_table_t *table, const char *key,
+ size_t length)
+{
+ ck_hash_table_item_t **place = ck_find_item_nc(table, key, length);
+ if (place == NULL) {
+ return NULL;
+ }
+
+ ck_hash_table_item_t *item = *place;
+ *place = NULL;
+ return item;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int ck_shallow_copy(const ck_hash_table_t *from, ck_hash_table_t **to)
+{
+ if (from == NULL || to == NULL) {
+ return -1;
+ }
+
+ *to = (ck_hash_table_t *)malloc(sizeof(ck_hash_table_t));
+
+ if (*to == NULL) {
+ ERR_ALLOC_FAILED;
+ return -2;
+ }
+ memset(*to, 0, sizeof(ck_hash_table_t));
+
+ // copy table count and table size exponent
+ (*to)->table_size_exp = from->table_size_exp;
+ (*to)->table_count = from->table_count;
+ assert((*to)->table_size_exp <= 32);
+
+ dbg_ck("Creating hash table for %u items.\n", from->table_count);
+ dbg_ck("Exponent: %u, number of tables: %u\n ",
+ (*to)->table_size_exp, (*to)->table_count);
+ dbg_ck("Table size: %u items, each %zu bytes, total %zu bytes\n",
+ hashsize((*to)->table_size_exp),
+ sizeof(ck_hash_table_item_t *),
+ hashsize((*to)->table_size_exp)
+ * sizeof(ck_hash_table_item_t *));
+
+ // create tables
+ for (uint t = 0; t < (*to)->table_count; ++t) {
+ dbg_ck("Creating table %u...\n", t);
+ (*to)->tables[t] = (ck_hash_table_item_t **)malloc(
+ hashsize((*to)->table_size_exp)
+ * sizeof(ck_hash_table_item_t *));
+ if ((*to)->tables[t] == NULL) {
+ ERR_ALLOC_FAILED;
+ for (uint i = 0; i < t; ++i) {
+ free((*to)->tables[i]);
+ }
+ free(*to);
+ return -2;
+ }
+
+ // copy the table
+ memcpy((*to)->tables[t], from->tables[t],
+ hashsize((*to)->table_size_exp)
+ * sizeof(ck_hash_table_item_t *));
+ }
+
+ // copy the stash - we must explicitly copy each stash item, but do not
+ // copy the ck_hash_table_item_t within them.
+ ck_stash_item_t *si = from->stash;
+ ck_stash_item_t **pos = &(*to)->stash;
+ dbg_ck_verb(stderr, "Copying hash table stash.\n");
+ while (si != NULL) {
+ ck_stash_item_t *si_new = (ck_stash_item_t *)
+ malloc(sizeof(ck_stash_item_t));
+ if (si_new == NULL) {
+ ERR_ALLOC_FAILED;
+ // delete tables
+ for (uint i = 0; i < (*to)->table_count; ++i) {
+ free((*to)->tables[i]);
+ }
+ // delete created stash items
+ si_new = (*to)->stash;
+ while (si_new != NULL) {
+ ck_stash_item_t *prev = si_new;
+ si_new = si_new->next;
+ free(prev);
+ }
+ free(*to);
+ return -2;
+ }
+
+ dbg_ck("Copying stash item: %p with item %p, ", si, si->item);
+ dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key);
+
+ si_new->item = si->item;
+ *pos = si_new;
+ pos = &si_new->next;
+ si = si->next;
+
+
+ dbg_ck("Old stash item: %p with item %p, ", si,
+ ((si == NULL) ? NULL : si->item));
+ if (si != NULL) {
+ dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key);
+ } else {
+ dbg_ck("\n");
+ }
+ dbg_ck("New stash item: %p with item %p, ", si_new,
+ si_new->item);
+ dbg_ck("key: %.*s\n", (int)si_new->item->key_length,
+ si_new->item->key);
+ }
+
+ *pos = NULL;
+
+ // there should be no item being hashed right now
+ /*! \todo This operation should not be done while inserting / rehashing.
+ */
+ assert(from->hashed == NULL);
+ (*to)->hashed = NULL;
+
+ // initialize rehash/insert mutex
+ pthread_mutex_init(&(*to)->mtx_table, NULL);
+
+ // copy the generation
+ (*to)->generation = from->generation;
+
+ // copy the hash functions
+ memcpy(&(*to)->hash_system, &from->hash_system, sizeof(us_system_t));
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int ck_apply(ck_hash_table_t *table,
+ void (*function)(ck_hash_table_item_t *item, void *data),
+ void *data)
+{
+ if (table == NULL || function == NULL) {
+ return -1;
+ }
+
+ /*! \todo Ensure that no insertion nor rehash is made during applying.*/
+
+ // apply the function to all items in all tables
+ for (int t = 0; t < table->table_count; ++t) {
+ for (int i = 0; i < hashsize(table->table_size_exp); ++i) {
+ function(table->tables[t][i], data);
+ }
+ }
+
+ // apply the function to the stash items
+ ck_stash_item_t *si = table->stash;
+ while (si != NULL) {
+ function(si->item, data);
+ si = si->next;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int ck_rehash(ck_hash_table_t *table)
+{
+ dbg_ck_hash("Rehashing items in table.\n");
+ SET_REHASHING_ON(&table->generation);
+
+ ck_stash_item_t *free_stash_items = NULL;
+
+ do {
+ // 1) Rehash items from stash
+ dbg_ck_rehash("Rehashing items from stash.\n");
+ ck_stash_item_t *item = table->stash;
+ ck_stash_item_t **item_place = &table->stash;
+ // terminate when at the end; this way the newly added items
+ // (added to the beginning) will be properly ignored
+ while (item != NULL) {
+ dbg_ck_rehash("Rehashing item with "
+ "key (length %zu): %.*s, generation: %hu, "
+ "table generation: %hu.\n", item->item->key_length,
+ (int)item->item->key_length, item->item->key,
+ GET_GENERATION(
+ item->item->timestamp),
+ GET_GENERATION(table->generation));
+
+ // put the hashed item to the prepared space
+ table->hashed = item->item;
+ item->item = NULL;
+ // we may use the place in the stash item as the free
+ // place for rehashing
+ if (ck_hash_item(table, &table->hashed, &item->item,
+ NEXT_GENERATION(table->generation)) != 0) {
+ // the free place was used
+ assert(item->item != NULL);
+ // we may leave the item there (in the stash)
+ assert(EQUAL_GENERATIONS(item->item->timestamp,
+ NEXT_GENERATION(table->generation)));
+ //assert(item->item == table->hashed);
+
+ item_place = &item->next;
+ item = item->next;
+ } else {
+ // the free place should be free
+ assert(item->item == NULL);
+ // and the item should be hashed too
+// assert(table->hashed == NULL);
+
+ // fix the pointer from the previous hash item
+ *item_place = item->next;
+ // and do not change the item place pointer
+
+ // put the stash item into list of free stash
+ // items
+ item->next = free_stash_items;
+ free_stash_items = item;
+
+ item = *item_place;
+ }
+ }
+
+ // 2) Rehash items from tables
+
+ // in case of failure, save the item in a temp variable
+ // which will be put to the stash
+ ck_hash_table_item_t *free = NULL;
+ assert(table->hashed == NULL);
+// ck_hash_table_item_t *old = table->hashed;
+
+ for (uint t = 0; t < table->table_count; ++t) {
+ uint rehashed = 0;
+
+ dbg_ck_rehash("Rehashing table %d.\n", t);
+
+ while (rehashed < hashsize(table->table_size_exp)) {
+
+ // if item's generation is the new generation,
+ // skip
+ if (table->tables[t][rehashed] == NULL
+ || !(EQUAL_GENERATIONS(
+ table->tables[t][rehashed]->timestamp,
+ table->generation))) {
+ dbg_ck_rehash("Skipping item.\n");
+ ++rehashed;
+ continue;
+ }
+
+ dbg_ck_rehash("Rehashing item with hash %u, "
+ "key (length %zu): %.*s, generation: %hu, "
+ "table generation: %hu.\n", rehashed,
+ table->tables[t][rehashed]->key_length,
+ (int)(table->tables[t][rehashed]->key_length),
+ table->tables[t][rehashed]->key,
+ GET_GENERATION(
+ table->tables[t][rehashed]->timestamp),
+ GET_GENERATION(table->generation));
+
+ // otherwise copy the item for rehashing
+ ck_put_item(&table->hashed, table->tables[t][rehashed]);
+ // clear the place so that this item will not
+ // get rehashed again
+ ck_clear_item(&table->tables[t][rehashed]);
+
+ dbg_ck_rehash("Table generation: %hu, next "
+ "generation: %hu.\n",
+ GET_GENERATION(table->generation),
+ NEXT_GENERATION(table->generation));
+
+ if (ck_hash_item(table, &table->hashed, &free,
+ NEXT_GENERATION(table->generation)) != 0) {
+ // loop occured
+ dbg_ck_hash("Hashing entered a loop."
+ "\n");
+ dbg_ck_rehash("Item with key %.*s "
+ "inserted into the free slot.\n",
+ free->key_length, free->key);
+
+ //assert(old == free);
+
+ // put the item into the stash, but
+ // try the free stash items first
+ if (free_stash_items != NULL) {
+ // take first
+ ck_stash_item_t *item =
+ free_stash_items;
+ free_stash_items = item->next;
+
+ item->item = free;
+ item->next = table->stash;
+ table->stash = item;
+ } else {
+ if (ck_add_to_stash(table, free)
+ != 0) {
+ ck_rollback_rehash(
+ table);
+ }
+ }
+
+ free = NULL;
+ table->hashed = NULL;
+ }
+ ++rehashed;
+ }
+ }
+
+ dbg_ck_rehash("Old table generation: %u\n",
+ GET_GENERATION(table->generation));
+ // rehashing completed, switch generation of the table
+ SET_NEXT_GENERATION(&table->generation);
+ dbg_ck_rehash("New table generation: %u\n",
+ GET_GENERATION(table->generation));
+ // generate new hash functions for the old generation
+ dbg_ck_rehash("Generating coeficients for generation: %u\n",
+ NEXT_GENERATION(table->generation));
+ us_next(&table->hash_system,
+ NEXT_GENERATION(table->generation));
+
+ } while (false /*! \todo Add proper condition!! */);
+
+ SET_REHASHING_OFF(&table->generation);
+
+ assert(table->hashed == NULL);
+
+
+ while (free_stash_items != NULL) {
+ ck_stash_item_t *item = free_stash_items;
+ free_stash_items = item->next;
+ assert(item->item == NULL);
+ free(item);
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Rehashes the whole table.
+ *
+ * \param table Hash table to be rehashed.
+ *
+ * \note While rehashing no item should be inserted as it will result in a
+ * deadlock.
+ *
+ * \retval 0 No error.
+ * \retval -1 Rehashing failed. Some items may have been already moved and the
+ * rehashing flag remains set.
+ *
+ * \todo What if the stash is reallocated during ck_hash_item()? We'd be using
+ * the old stash for saving items! The old stash would not get deallocated
+ * (due to RCU - maybe put some rcu_read_lock() here), but the item
+ * would not be saved into the new stash!
+ * Maybe add a function for getting a pointer to particular item from
+ * the dynamic array and protect it using rcu_read_lock().
+ * Other option: Do not use pointer to an item in stash in the call to
+ * ck_hash_item(). Use some new place & put the item to the stash
+ * afterwards, protecting it using rcu_read_lock() and rcu_assign_pointer.
+ */
+//int ck_rehash(ck_hash_table_t *table)
+//{
+// dbg_ck_rehash("Rehashing items in table.\n");
+// SET_REHASHING_ON(&table->generation);
+
+// // we already have functions for the next generation, begin rehashing
+// // we wil use the last item in the buffer as free cell for hashing
+// assert(da_try_reserve(&table->stash, 1) == 0);
+// ck_hash_table_item_t *old = (ck_hash_table_item_t *)
+// (malloc(sizeof(ck_hash_table_item_t)));
+
+// do {
+// dbg_ck_hash("Rehash!\n");
+
+// if (da_get_count(&table->stash) > STASH_SIZE) {
+// dbg_ck_hash("STASH RESIZED!!! (new stash size: %d)\n",
+// da_get_count(&table->stash));
+// }
+
+// // rehash items from stash, starting from the last old item
+// int stash_i = da_get_count(&table->stash) - 1;
+// while (stash_i >= 0) {
+// // if item's generation is the new generation, skip
+// if (STASH_ITEMS(&table->stash)[stash_i] == NULL
+// || !(EQUAL_GENERATIONS(STASH_ITEMS(&table->stash)
+// [stash_i]->timestamp,
+// table->generation))) {
+// dbg_ck_rehash("Skipping item.\n");
+// --stash_i;
+// continue;
+// }
+
+// dbg_ck_rehash("Rehashing item from buffer position %u"
+// ", key (length %u): %.*s, generation: "
+// "%hu, table generation: %hu.\n",
+// stash_i,
+// STASH_ITEMS(&table->stash)[stash_i]->key_length,
+// (int)STASH_ITEMS(&table->stash)[stash_i]->key_length,
+// STASH_ITEMS(&table->stash)[stash_i]->key,
+// GET_GENERATION(
+// STASH_ITEMS(&table->stash)[stash_i]->timestamp),
+// GET_GENERATION(table->generation));
+
+// // otherwise copy the item for rehashing
+// ck_put_item(&old, STASH_ITEMS(&table->stash)[stash_i]);
+// // clear the place so that this item will not get
+// // rehashed again
+// ck_clear_item(&STASH_ITEMS(&table->stash)[stash_i]);
+// da_release(&table->stash, 1);
+
+// // there should be at least one place in the stash
+// assert(da_try_reserve(&table->stash, 1) == 0);
+// da_reserve(&table->stash, 1);
+
+// assert(STASH_ITEMS(&table->stash)[stash_i] == NULL);
+
+// // and start rehashing
+// if (ck_hash_item(table, &old,
+// &STASH_ITEMS(&table->stash)[stash_i],
+// NEXT_GENERATION(table->generation)) != 0) {
+// // loop occured
+// dbg_ck_hash("Hashing entered a loop.\n");
+
+// dbg_ck_rehash("Item with key %.*s inserted "
+// "into the stash on position %d.\n",
+// STASH_ITEMS(&table->stash)
+// [stash_i]->key_length,
+// STASH_ITEMS(&table->stash)
+// [stash_i]->key,
+// da_get_count(&table->stash));
+
+// // hashing unsuccessful, the item was inserted
+// // into the stash
+// da_occupy(&table->stash, 1);
+// assert(STASH_ITEMS(&table->stash)[stash_i]
+// != NULL);
+
+// // if only one place left, resize the stash
+// // TODO: Why???
+// if (da_reserve(&table->stash, 2) < 0) {
+// // stash could not be resized => !!!
+// dbg_ck_hash("Failed to rehash items "
+// "from "
+// "table, no other rehash possible!\n");
+// // so rollback
+// ck_rollback_rehash(table);
+// // clear the 'old' item
+// ck_clear_item(&old);
+// return -1;
+// }
+// }
+
+// // clear the 'old' item
+// ck_clear_item(&old);
+// // decrement the index
+// --stash_i;
+// }
+
+// uint i = 0;
+// while (i < da_get_count(&table->stash)) {
+// assert(STASH_ITEMS(&table->stash)[i] != NULL);
+// ++i;
+// }
+// dbg_ck_hash("OK\n");
+// assert(da_try_reserve(&table->stash, 1) == 0);
+// assert(STASH_ITEMS(&table->stash)[da_get_count(&table->stash)]
+// == NULL);
+
+// // rehash items from hash tables
+// for (uint t = TABLE_FIRST;
+// t <= TABLE_LAST(table->table_count); ++t) {
+// dbg_ck_rehash("Rehashing items from table %d.\n",
+// t + 1);
+// uint rehashed = 0;
+
+// while (rehashed < hashsize(table->table_size_exp)) {
+
+// // if item's generation is the new generation,
+// // skip
+// if (table->tables[t][rehashed] == NULL
+// || !(EQUAL_GENERATIONS(
+// table->tables[t][rehashed]->timestamp,
+// table->generation))) {
+// dbg_ck_rehash("Skipping item.\n");
+// ++rehashed;
+// continue;
+// }
+
+// dbg_ck_rehash("Rehashing item with hash %u, "
+// "key (length %u): %.*s, generation: %hu, "
+// "table generation: %hu.\n", rehashed,
+// table->tables[t][rehashed]->key_length,
+// (int)(table->tables[t][rehashed]->key_length),
+// table->tables[t][rehashed]->key,
+// GET_GENERATION(
+// table->tables[t][rehashed]->timestamp),
+// GET_GENERATION(table->generation));
+
+// // otherwise copy the item for rehashing
+// ck_put_item(&old, table->tables[t][rehashed]);
+// // clear the place so that this item will not
+// // get rehashed again
+// ck_clear_item(&table->tables[t][rehashed]);
+
+// dbg_ck_rehash("Table generation: %hu, next "
+// "generation: %hu.\n",
+// GET_GENERATION(table->generation),
+// NEXT_GENERATION(table->generation));
+
+// // and start rehashing
+// assert(&old != &STASH_ITEMS(&table->stash)[
+// da_get_count(&table->stash)]);
+// assert(da_try_reserve(&table->stash, 1) == 0);
+// da_reserve(&table->stash, 1);
+
+// if (ck_hash_item(table, &old,
+// &STASH_ITEMS(&table->stash)[
+// da_get_count(&table->stash)],
+// NEXT_GENERATION(table->generation)) != 0) {
+// // loop occured
+// dbg_ck_hash("Hashing entered a loop."
+// "\n");
+// dbg_ck_rehash("Item with key %.*s "
+// "inserted into the stash on position "
+// "%d.\n", STASH_ITEMS(&table->stash)[
+// da_get_count(&table->stash)]
+// ->key_length,
+// STASH_ITEMS(&table->stash)[
+// da_get_count(&table->stash)]->key,
+// da_get_count(&table->stash));
+
+// assert(STASH_ITEMS(&table->stash)[
+// da_get_count(&table->stash)] != NULL);
+// // loop occured, the item is already at
+// // its new place in the buffer, so just
+// // increment the index
+// da_occupy(&table->stash, 1);
+
+// // if only one place left, resize the
+// // stash TODO: Why?
+// if (da_reserve(&table->stash, 2) < 0) {
+// // stash could not be resized
+// dbg_ck_hash("Failed to rehash"
+// " items from table, no other "
+// "rehash possible!\n");
+// // so rollback
+// ck_rollback_rehash(table);
+// // clear the 'old' item
+// ck_clear_item(&old);
+// return -1;
+// }
+// }
+// ++rehashed;
+// }
+// }
+
+// dbg_ck_rehash("Old table generation: %u\n",
+// GET_GENERATION(table->generation));
+// // rehashing completed, switch generation of the table
+// SET_NEXT_GENERATION(&table->generation);
+// dbg_ck_rehash("New table generation: %u\n",
+// GET_GENERATION(table->generation));
+// // generate new hash functions for the old generation
+// dbg_ck_rehash("Generating coeficients for generation: %u\n",
+// NEXT_GENERATION(table->generation));
+// us_next(NEXT_GENERATION(table->generation));
+
+// // repeat rehashing while there are more items in the stash than
+// // its initial size
+// if (da_get_count(&table->stash) > STASH_SIZE) {
+// dbg_ck_rehash("Rehashing again!\n");
+// }
+// } while (da_get_count(&table->stash) > STASH_SIZE);
+
+// SET_REHASHING_OFF(&table->generation);
+
+// return 0;
+//}
+
+/*----------------------------------------------------------------------------*/
+
+void ck_dump_table(const ck_hash_table_t *table)
+{
+#ifdef CUCKOO_DEBUG
+ uint i = 0;
+ dbg_ck("----------------------------------------------\n");
+ dbg_ck("Hash table dump:\n\n");
+ dbg_ck("Size of each table: %u\n\n", hashsize(table->table_size_exp));
+
+ for (uint t = 0; t < table->table_count; ++t) {
+ dbg_ck("Table %d:\n", t + 1);
+
+ for (i = 0; i < hashsize(table->table_size_exp); i++) {
+ dbg_ck("Hash: %u, Key: %.*s, Value: %p.\n", i,
+ (int)(table->tables[t])[i]->key_length,
+ (table->tables[t])[i]->key,
+ (table->tables[t])[i]->value);
+ }
+ }
+
+ dbg_ck("Stash:\n");
+// for (i = 0; i < da_get_count(&table->stash); ++i) {
+// dbg_ck("Index: %u, Key: %.*s Value: %p.\n", i,
+// ((ck_hash_table_item_t **)
+// da_get_items(&table->stash))[i]->key_length,
+// ((ck_hash_table_item_t **)
+// da_get_items(&table->stash))[i]->key,
+// ((ck_hash_table_item_t **)
+// da_get_items(&table->stash))[i]->value);
+// }
+ ck_stash_item_t *item = table->stash;
+ while (item != NULL) {
+ dbg_ck("Hash: %u, Key: %.*s, Value: %p.\n", i,
+ (int)item->item->key_length, item->item->key,
+ item->item->value);
+ item = item->next;
+ }
+
+ dbg_ck("\n");
+#endif
+}
diff --git a/src/libknot/hash/cuckoo-hash-table.h b/src/libknot/hash/cuckoo-hash-table.h
new file mode 100644
index 0000000..dd78294
--- /dev/null
+++ b/src/libknot/hash/cuckoo-hash-table.h
@@ -0,0 +1,333 @@
+/*!
+ * \file cuckoo-hash-table.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Implementation of Cuckoo hashing scheme.
+ *
+ * Uses d-ary Cuckoo hashing with stash.
+ *
+ * \todo Maybe provide some way to resize the whole table if the number of items
+ * grows too much.
+ * \todo Check size of integers, the table size may be larger than unsigned int.
+ * \todo Maybe do not return ck_hash_table_item from ck_find_item(), but only
+ * its value.
+ * \todo When hashing an item, only the first table is tried for this item.
+ * We may try all tables. (But it is not neccessary.)
+ *
+ * \addtogroup hashing
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_CUCKOO_HASH_TABLE_H_
+#define _KNOT_CUCKOO_HASH_TABLE_H_
+
+#include <stdint.h> /* uint32_t */
+#include <stdlib.h> /* size_t */
+#include <pthread.h>
+
+#include "hash/universal-system.h"
+#include "common/dynamic-array.h"
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Macro for getting one hash table size. */
+#define hashsize(n) ((uint32_t)1 << (n))
+
+/*!
+ * \brief Max number of hash tables - must be the same as number of the hash
+ * functions in each generation of the universal system.
+ */
+#define MAX_TABLES US_FNC_COUNT
+
+/*! \brief Default stash size. */
+static const uint STASH_SIZE = 10;
+
+/*! \brief Maximum stash size. When achieved, rehashing is needed. */
+static const uint STASH_SIZE_MAX = 30;
+
+/*----------------------------------------------------------------------------*/
+/* Public structures */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Structure for storing the hashed data.
+ */
+struct ck_hash_table_item {
+ const char *key; /*!< Key of the item, used for hashing. */
+
+ size_t key_length; /*!< Length of the key in octets. */
+
+ void *value; /*!< The actual item stored in the table. */
+
+ /*!
+ * \brief Flags. Currently used for keeping the generation of the item,
+ * i.e. the generation of the functions used for hashing this
+ * item.
+ *
+ * Form: 000000xy;
+ * xy - generation; may be 01 (1) or 10 (2).
+ */
+ uint8_t timestamp;
+};
+
+typedef struct ck_hash_table_item ck_hash_table_item_t;
+
+struct ck_stash_item {
+ ck_hash_table_item_t *item;
+ struct ck_stash_item *next;
+};
+
+typedef struct ck_stash_item ck_stash_item_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Hash table structure which uses cuckoo hashing.
+ *
+ * Keys are expected to be strings of characters (char *), not necesarily
+ * null-terminated. It uses the Fowler/Noll/Vo (FNV) hash function to
+ * obtain a 32bit unsigned integer from the character data and a function
+ * randomly chosen from an universal system (see universal-system.h) to obtain
+ * the final hash. The FNV hash was taken from
+ * http://home.comcast.net/~bretm/hash/6.html and the universal system is
+ * constructed according to Katajainen J., Lykke M., Experiments with universal
+ * hashing (obtained from
+ * http://www.diku.dk/OLD/publikationer/tekniske.rapporter/rapporter/96-08.pdf).
+ *
+ * The table uses either 3-ary or 4-ary cuckoo hashing (and thus 3 or 4 tables)
+ * with stash, according to the number of items provided to ck_create_table()
+ * function. The number of table pointers is however set to be the larger value
+ * (4) always, so the \a tables array may be statically allocated. Size of one
+ * table is always a power of 2 (due to the character of the hash function).
+ * The stash has a default size STASH_SIZE, but can be resized if needed.
+ * However, the resizing is only done in rehashing process, if the items do not
+ * fit into the table and the original stash.
+ *
+ * Rehashing is done when the stash gets full (actually, last item is always
+ * free and is used in the rehashing process as a temporary variable).
+ */
+struct ck_hash_table {
+ uint table_count; /*!< Actual number of hash tables used. */
+
+ /*!
+ * \brief Exponent of one table's size (2^table_size_exp is table size).
+ */
+ int table_size_exp;
+
+ ck_hash_table_item_t **tables[MAX_TABLES]; /*!< Array of hash tables. */
+
+ //da_array_t stash; /*!< Stash implemented as a dynamic array. */
+ ck_stash_item_t *stash;
+
+ /*! \brief Temporary storage for item being hashed. */
+ ck_hash_table_item_t *hashed;
+
+ /*! \brief Mutex for avoiding multiple insertions / rehashes at once. */
+ pthread_mutex_t mtx_table;
+
+ /*!
+ * \brief Flags used for determining which hash functions are currently
+ * used
+ *
+ * Form: 00000xyz.
+ * x - rehash flag (1 if rehashing is in progress)
+ * yz - generation (may be 10 = 2, or 01 = 1)
+ *
+ * There are always two sets of hash functions available via the
+ * us_hash() function (see universal-hashing.h). Normally all items in
+ * the table are hashed using one set of functions. However, during
+ * rehash, the other set is used for rehashing. In this case the rehash
+ * flag (x) is set, so the lookup function (ck_find_item()) tries to use
+ * both sets of functions when searching for item.
+ */
+ uint8_t generation;
+
+ us_system_t hash_system; /*!< Universal system of hash functions. */
+
+ size_t items;
+ size_t items_in_stash;
+};
+
+typedef struct ck_hash_table ck_hash_table_t;
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates and initializes the hash table structure.
+ *
+ * All hash tables are allocated and their items initialized to 0 (NULL).
+ * A stash of default size is also created. The \a generation flags are set to
+ * 0.
+ *
+ * \param items Number of items to be hashed to the table. This number
+ * determines the size of the hash table that will be created.
+ *
+ *
+ * \return Pointer to the initialized hash table.
+ */
+ck_hash_table_t *ck_create_table(uint items);
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Destroys the whole hash table together with the saved values.
+ *
+ * \param table Pointer to pointer to the hash table.
+ * \param dtor_value Destructor function for the values that are be stored in
+ * the hash table. Set to NULL if you do not want the values
+ * to be deleted.
+ * \param delete_key Set to 0 if you do not want the function to delete the
+ * key of the item (e.g. when used elsewhere). Set to any
+ * other value otherwise.
+ *
+ * \note Make sure the table and its items are not used anymore when calling
+ * this function.
+ */
+void ck_destroy_table(ck_hash_table_t **table,
+ void (*dtor_value)(void *value), int delete_key);
+
+/*!
+ * \brief Destroys the table structures, but does not remove the individual
+ * hash table items.
+ */
+void ck_table_free(ck_hash_table_t **table);
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Inserts item into the hash table.
+ *
+ * Insertion starts always by trying to hash the item into the first table. The
+ * possible displaced item is then hashed into randomly chosen other table,
+ * etc., until a free place is found or a loop occured. A loop occurs when one
+ * position in one table is tried more than twice.
+ *
+ * \param table Hash table the item should be inserted into.
+ * \param key Item's key. It can be any string of octets. The key is not copied
+ * by the function.
+ * \param length Length of the key in bytes (octets).
+ * \param value Pointer to the actual item to be inserted into the hash table.
+ *
+ * \note This function does not copy the key.
+ * \note This function may trigger rehash of the whole table in case the stash
+ * gets full.
+ *
+ * \retval 0 No error.
+ * \retval -1 Insertion failed. This may occur only when the rehashing fails.
+ * In this case it is necessary to somehow manually force another
+ * rehash as no other rehash would be possible.
+ */
+int ck_insert_item(ck_hash_table_t *table, const char *key, size_t length,
+ void *value);
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Finds item in table.
+ *
+ * \param table Hash table to search in.
+ * \param key Key of the item. It can be an arbitrary string of octets.
+ * \param length Length of the key in bytes (octets).
+ *
+ * \return Pointer to the item if found. NULL otherwise.
+ */
+const ck_hash_table_item_t *ck_find_item(const ck_hash_table_t *table,
+ const char *key, size_t length);
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Updates item with the given key by replacing its value.
+ *
+ * The update process is synchronized using RCU mechanism, so the old item's
+ * value will not be deleted while some thread is using it.
+ *
+ * \param table Hash table where to search for the item.
+ * \param key Key of the item to be updated. It can be an arbitrary string of
+ * octets.
+ * \param length Length of the key in bytes (octets).
+ * \param new_value New value for the item with key \a key.
+ * \param dtor_value Destructor function for the values that are be stored in
+ * the hash table. Set to NULL if you do not want the values
+ * to be deleted.
+ *
+ * \retval 0 If successful.
+ * \retval -1 If the item was not found in the table. No changes are made.
+ */
+int ck_update_item(const ck_hash_table_t *table, const char *key, size_t length,
+ void *new_value, void (*dtor_value)(void *value));
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Removes item with the given key from table.
+ *
+ * The deletion process is synchronized using RCU mechanism, so the old item
+ * will not be deleted while some thread is using it.
+ *
+ * \param table Hash table where to search for the item.
+ * \param key Key of the item to be removed. It can be an arbitrary string of
+ * octets.
+ * \param length Length of the key in bytes (octets).
+ * \param dtor_value Destructor function for the values that are be stored in
+ * the hash table. Set to NULL if you do not want the values
+ * to be deleted.
+ * \param delete_key Set to 0 if you do not want the function to delete the
+ * key of the item (e.g. when used elsewhere). Set to any
+ * other value otherwise.
+ *
+ * \retval 0 If successful.
+ * \retval -1 If the item was not found in the table.
+ */
+int ck_delete_item(const ck_hash_table_t *table, const char *key, size_t length,
+ void (*dtor_value)(void *value), int delete_key);
+
+ck_hash_table_item_t *ck_remove_item(ck_hash_table_t *table, const char *key,
+ size_t length);
+
+/*!
+ * \brief Creates a shallow copy of the cuckoo hash table.
+ *
+ * This function creates just the ck_hash_table_t structure and its tables and
+ * stash. It does not copy individual ck_hash_table_item_t structures.
+ *
+ * \param from Table to copy.
+ * \param to The new copy will be stored here.
+ *
+ * \retval 0 if successful.
+ * \retval
+ */
+int ck_shallow_copy(const ck_hash_table_t *from, ck_hash_table_t **to);
+
+int ck_apply(ck_hash_table_t *table,
+ void (*function)(ck_hash_table_item_t *item, void *data),
+ void *data);
+
+/*----------------------------------------------------------------------------*/
+
+int ck_rehash(ck_hash_table_t *table);
+
+// for testing purposes only
+int ck_resize_table(ck_hash_table_t *table);
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Dumps the whole hash table to the standard output.
+ */
+void ck_dump_table(const ck_hash_table_t *table);
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* _KNOT_CUCKOO_HASH_TABLE_H_ */
+
+/*! @} */
diff --git a/src/libknot/hash/hash-functions.c b/src/libknot/hash/hash-functions.c
new file mode 100644
index 0000000..a33dd6b
--- /dev/null
+++ b/src/libknot/hash/hash-functions.c
@@ -0,0 +1,241 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "hash-functions.h"
+
+/*--------------------------------- FNV HASH ---------------------------------*/
+
+unsigned long int fnv_hash(const char *data, int size, int bits)
+{
+ int shift, i;
+ unsigned long int mask;
+ unsigned long int hash = 2166136261;
+
+ if (bits == -1) {
+ shift = 0;
+ mask = 0xFFFFFFFF;
+ } else {
+ shift = 32 - bits;
+ mask = (1U << shift) - 1U;
+ }
+
+ for (i = 0; i < size; i++) {
+ hash = (hash * 16777619) ^ data[i];
+ }
+
+ if (shift == 0) {
+ return hash;
+ }
+
+ return (hash ^(hash >> shift)) & mask;
+}
+
+/*------------------------------- JENKINS HASH -------------------------------*/
+
+/* The mixing step */
+/*
+#define mix(a,b,c) \
+ { \
+ a=a-b; a=a-c; a=a^(c>>13); \
+ b=b-c; b=b-a; b=b^(a<<8); \
+ c=c-a; c=c-b; c=c^(b>>13); \
+ a=a-b; a=a-c; a=a^(c>>12); \
+ b=b-c; b=b-a; b=b^(a<<16); \
+ c=c-a; c=c-b; c=c^(b>>5); \
+ a=a-b; a=a-c; a=a^(c>>3); \
+ b=b-c; b=b-a; b=b^(a<<10); \
+ c=c-a; c=c-b; c=c^(b>>15); \
+ }
+*/
+
+///* The whole new hash function */
+//u4 jhash(register u1 *k, u4 length, u4 initval)
+//{
+// register u4 a, b, c; /* the internal state */
+// u4 len; /* how many key bytes still need mixing */
+
+// /* Set up the internal state */
+// len = length;
+// a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+// c = initval; /* variable initialization of internal state */
+
+// /*---------------------------------------- handle most of the key */
+// while (len >= 12) {
+// a = a + (k[0] + ((u4)k[1] << 8)
+// + ((u4)k[2] << 16) + ((u4)k[3] << 24));
+// b = b + (k[4] + ((u4)k[5] << 8)
+// + ((u4)k[6] << 16) + ((u4)k[7] << 24));
+// c = c + (k[8] + ((u4)k[9] << 8)
+// + ((u4)k[10] << 16) + ((u4)k[11] << 24));
+// mix(a, b, c);
+// k = k + 12;
+// len = len - 12;
+// }
+
+// /*------------------------------------- handle the last 11 bytes */
+// c = c + length;
+// switch (len) { /* all the case statements fall through */
+// case 11:
+// c = c + ((u4)k[10] << 24);
+// case 10:
+// c = c + ((u4)k[9] << 16);
+// case 9 :
+// c = c + ((u4)k[8] << 8);
+// /* the first byte of c is reserved for the length */
+// case 8 :
+// b = b + ((u4)k[7] << 24);
+// case 7 :
+// b = b + ((u4)k[6] << 16);
+// case 6 :
+// b = b + ((u4)k[5] << 8);
+// case 5 :
+// b = b + k[4];
+// case 4 :
+// a = a + ((u4)k[3] << 24);
+// case 3 :
+// a = a + ((u4)k[2] << 16);
+// case 2 :
+// a = a + ((u4)k[1] << 8);
+// case 1 :
+// a = a + k[0];
+// /* case 0: nothing left to add */
+// }
+// mix(a, b, c);
+// /*-------------------------------------------- report the result */
+// return c;
+//}
+
+
+
+#define hashsize(n) ((ub4)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+
+/*
+--------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+For every delta with one or two bits set, and the deltas of all three
+ high bits or all three low bits, whether the original value of a,b,c
+ is almost all zero or is uniformly distributed,
+* If mix() is run forward or backward, at least 32 bits in a,b,c
+ have at least 1/4 probability of changing.
+* If mix() is run forward, every bit of c will change between 1/3 and
+ 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
+mix() was built out of 36 single-cycle latency instructions in a
+ structure that could supported 2x parallelism, like so:
+ a -= b;
+ a -= c; x = (c>>13);
+ b -= c; a ^= x;
+ b -= a; x = (a<<8);
+ c -= a; b ^= x;
+ c -= b; x = (b>>13);
+ ...
+ Unfortunately, superscalar Pentiums and Sparcs can't take advantage
+ of that parallelism. They've also turned some of those single-cycle
+ latency instructions into multi-cycle latency instructions. Still,
+ this is the fastest good hash I could find. There were about 2^^68
+ to choose from. I only looked at a billion or so.
+--------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= b; a -= c; a ^= (c>>13); \
+ b -= c; b -= a; b ^= (a<<8); \
+ c -= a; c -= b; c ^= (b>>13); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<16); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>3); \
+ b -= c; b -= a; b ^= (a<<10); \
+ c -= a; c -= b; c ^= (b>>15); \
+}
+
+/*
+--------------------------------------------------------------------
+hash() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ len : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Every 1-bit and 2-bit delta achieves avalanche.
+About 6*len+35 instructions.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (ub1 **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
+
+By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+--------------------------------------------------------------------
+*/
+
+ub4 jhash(k, length, initval)
+register ub1 *k; /* the key */
+register ub4 length; /* the length of the key */
+register ub4 initval; /* the previous hash, or an arbitrary value */
+{
+ register ub4 a,b,c,len;
+
+ /* Set up the internal state */
+ len = length;
+ a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+ c = initval; /* the previous hash value */
+
+ /*---------------------------------------- handle most of the key */
+ while (len >= 12)
+ {
+ a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
+ b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
+ c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
+ mix(a,b,c);
+ k += 12; len -= 12;
+ }
+
+ /*------------------------------------- handle the last 11 bytes */
+ c += length;
+ switch(len) /* all the case statements fall through */
+ {
+ case 11: c+=((ub4)k[10]<<24);
+ case 10: c+=((ub4)k[9]<<16);
+ case 9 : c+=((ub4)k[8]<<8);
+ /* the first byte of c is reserved for the length */
+ case 8 : b+=((ub4)k[7]<<24);
+ case 7 : b+=((ub4)k[6]<<16);
+ case 6 : b+=((ub4)k[5]<<8);
+ case 5 : b+=k[4];
+ case 4 : a+=((ub4)k[3]<<24);
+ case 3 : a+=((ub4)k[2]<<16);
+ case 2 : a+=((ub4)k[1]<<8);
+ case 1 : a+=k[0];
+ /* case 0: nothing left to add */
+ }
+ mix(a,b,c);
+ /*-------------------------------------------- report the result */
+ return c;
+}
+
+#undef hashsize
+#undef hashmask
+
diff --git a/src/libknot/hash/hash-functions.h b/src/libknot/hash/hash-functions.h
new file mode 100644
index 0000000..f23730b
--- /dev/null
+++ b/src/libknot/hash/hash-functions.h
@@ -0,0 +1,85 @@
+/*!
+ * \file hash-functions.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Various hash functions.
+ *
+ * All of the hash functions are downloaded from various sources.
+ *
+ * \todo Add references to sources.
+ *
+ * \addtogroup hashing
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_HASH_FUNCTIONS_H_
+#define _KNOT_HASH_FUNCTIONS_H_
+
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * Fowler / Noll / Vo Hash (FNV Hash)
+ * http://www.isthe.com/chongo/tech/comp/fnv/
+ *
+ * This is an implementation of the algorithms posted above.
+ * This file is placed in the public domain by Peter Wemm.
+ *
+ * $FreeBSD: src/sys/sys/fnv_hash.h,v 1.2.2.1 2001/03/21 10:50:59 peter Exp $
+ */
+
+typedef uint32_t Fnv32_t;
+
+#define FNV1_32_INIT ((Fnv32_t) 33554467UL)
+
+#define FNV_32_PRIME ((Fnv32_t) 0x01000193UL)
+
+static __inline Fnv32_t
+fnv_32_buf(const void *buf, size_t len, Fnv32_t hval)
+{
+ const uint8_t *s = (const uint8_t *)buf;
+
+ while (len-- != 0) {
+ hval *= FNV_32_PRIME;
+ hval ^= *s++;
+ }
+ return hval;
+}
+
+/*!
+ * \brief Jenkins hash function.
+ *
+ * Downloaded from http://burtleburtle.net/bob/hash/evahash.html
+ *
+ * \param k Data to hash
+ * \param length Size of the data in bytes.
+ * \param initval The previous hash or an arbitrary value.
+ *
+ * \return Hash of the data.
+ *
+ * \todo Add source.
+ */
+typedef unsigned long int ub4; /* unsigned 4-byte quantities */
+typedef unsigned char ub1; /* unsigned 1-byte quantities */
+
+ub4 jhash(register ub1 *k, register ub4 length, register ub4 initval);
+
+#endif /* _KNOT_HASH_FUNCTIONS_H_ */
+
+/*! @} */
diff --git a/src/libknot/hash/universal-system.c b/src/libknot/hash/universal-system.c
new file mode 100644
index 0000000..096974c
--- /dev/null
+++ b/src/libknot/hash/universal-system.c
@@ -0,0 +1,116 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <limits.h>
+#include <stdint.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "universal-system.h"
+#include "common.h"
+#include "util/utils.h"
+
+/*----------------------------------------------------------------------------*/
+
+const uint MAX_UINT_EXP = 32;
+const unsigned long MAX_UINT_MY = UINT32_MAX; /* 4294967295 */
+
+/*----------------------------------------------------------------------------*/
+/* Private functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Generates new set of coeficients.
+ *
+ * \param system Universal system to generate the coeficients for.
+ * \param from First coeficient to be replaced.
+ * \param to Up to this the coeficients will be replaced.
+ */
+static void us_generate_coefs(us_system_t *system, uint from, uint to)
+{
+ assert(system != NULL);
+
+ for (uint i = from; i < to; ++i) {
+ int used = 0;
+
+ do {
+ // generate random odd number
+ system->coefs[i] = knot_quick_rand() % MAX_UINT_MY;
+ if (system->coefs[i] % 2 == 0) {
+ system->coefs[i] = (system->coefs[i] == 0)
+ ? 1
+ : system->coefs[i] - 1;
+ }
+ // check if this coeficient is already used
+ uint j = from;
+ while (used == 0 && j < i) {
+ if (system->coefs[j++] == system->coefs[i]) {
+ used = 1;
+ }
+ }
+ // if already used, generate again
+ } while (used != 0);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* Public functions */
+/*----------------------------------------------------------------------------*/
+
+void us_initialize(us_system_t *system)
+{
+ assert(system != NULL);
+ assert(UINT_MAX == MAX_UINT_MY);
+
+ // Initialize both generations of functions by generating random odd
+ // numbers
+ us_generate_coefs(system, 0, US_FNC_COUNT * GEN_COUNT);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \note \a generation starts from 1
+ */
+int us_next(us_system_t *system, uint generation)
+{
+ assert(system != NULL);
+ // generate new coeficients for the new generation
+ us_generate_coefs(system, (generation - 1) * US_FNC_COUNT,
+ generation * US_FNC_COUNT);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint32_t us_hash(const us_system_t *system, uint32_t value, uint table_exp,
+ uint fnc, uint generation)
+{
+ /*
+ * multiplication should overflow if larger than MAX_UINT
+ * this is the same as (coef * value) mod MAX_UINT
+ *
+ * TODO: maybe we should not rely on this
+ */
+ assert(system != NULL);
+ assert(table_exp <= 32);
+ assert(fnc < US_FNC_COUNT);
+ assert(generation <= GEN_COUNT);
+
+ return ((system->coefs[((generation - 1) * US_FNC_COUNT) + fnc] * value)
+ >> (MAX_UINT_EXP - table_exp));
+}
diff --git a/src/libknot/hash/universal-system.h b/src/libknot/hash/universal-system.h
new file mode 100644
index 0000000..25330de
--- /dev/null
+++ b/src/libknot/hash/universal-system.h
@@ -0,0 +1,109 @@
+/*!
+ * \file universal-system.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * This file provides interface to a 2-universal system of hash functions that
+ * hash from 32-bit unsigned integer to a 32-bit unsigned integer within a given
+ * range. The range is always a power of two and is given by the exponent (see
+ * function us_hash().
+ *
+ * Before using the system, it must be initialized by calling us_initialize().
+ * The system stores 2 sets (generations), each of US_FNC_COUNT functions.
+ * For generating a new set of coeficients (i.e. hash functions) use the
+ * us_next() function.
+ *
+ * For hashing use the us_hash() function.
+ *
+ * \todo What if all numbers are tried and still need rehash?
+ * (that means 2mld rehashes - we can probably live with that ;)
+ * \todo Consider counting generations from 0, will be easier!
+ * \todo Check out some better random number generator.
+ *
+ * \addtogroup hashing
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_UNIVERSAL_SYSTEM_H_
+#define _KNOT_UNIVERSAL_SYSTEM_H_
+
+#include <stdint.h>
+#include "common.h"
+
+
+enum { US_FNC_COUNT = 4 /*!< Number of functions for one generation. */ };
+
+enum { GEN_COUNT = 2 /*!< Number of generations. */ };
+
+/*----------------------------------------------------------------------------*/
+/*! \brief Analytically defined universal system of hashing functions. */
+struct us_system {
+ /*! \brief Coeficients for the functions */
+ uint coefs[US_FNC_COUNT * GEN_COUNT];
+};
+
+typedef struct us_system us_system_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Initializes the universal system by generating coeficients for all
+ * hash functions and all generations.
+ *
+ * \param system Universal system to be used.
+ */
+void us_initialize(us_system_t *system);
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Generates new hash functions' coeficients for the given \a generation.
+ *
+ * \param system Universal system to be used.
+ * \param generation Generation for which to generate the new coeficients.
+ *
+ * \return 0
+ */
+int us_next(us_system_t *system, uint generation);
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Hashes the \a value using the given \a exponent and function.
+ *
+ * The actual formula of the hash is:
+ * h = ((coef * value) mod 2^32) / 2^(32 - table_exp)
+ * where \a coef is the proper coeficient.
+ *
+ * \param system Universal system to be used.
+ * \param value Value to be hashed.
+ * \param table_exp Determines the upper bound for the result - the hash will
+ * be between 0 and 2^(32 - table_exp).
+ * \param fnc Which function from the set should be used.
+ * \param generation Which set (generation) of functions should be used.
+ *
+ * \todo Make inline?
+ *
+ * \return Hash value (32bit unsigned).
+ */
+uint32_t us_hash(const us_system_t *system, uint32_t value, uint table_exp,
+ uint fnc, uint generation);
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* _KNOT_UNIVERSAL_SYSTEM_H_ */
+
+/*! @} */
diff --git a/src/libknot/libknot.h b/src/libknot/libknot.h
new file mode 100644
index 0000000..a401be7
--- /dev/null
+++ b/src/libknot/libknot.h
@@ -0,0 +1,48 @@
+/*!
+ * \file libknot.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief Convenience header for including whole library.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_LIBKNOT_H_
+#define _KNOT_LIBKNOT_H_
+
+#include "consts.h"
+#include "util/descriptor.h"
+#include "dname.h"
+#include "edns.h"
+#include "zone/node.h"
+#include "nsec3.h"
+#include "util/wire.h"
+#include "rdata.h"
+#include "packet/response.h"
+#include "rrset.h"
+#include "util/tolower.h"
+#include "util/utils.h"
+#include "zone/zone.h"
+#include "zone/zonedb.h"
+#include "util/error.h"
+
+#endif
+
+/*! @} */
diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c
new file mode 100644
index 0000000..f88f802
--- /dev/null
+++ b/src/libknot/nameserver/name-server.c
@@ -0,0 +1,3663 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <sys/time.h>
+
+#include <urcu.h>
+
+#include "nameserver/name-server.h"
+#include "updates/xfr-in.h"
+
+#include "util/error.h"
+#include "libknot.h"
+#include "util/debug.h"
+#include "packet/packet.h"
+#include "packet/response.h"
+#include "packet/query.h"
+#include "consts.h"
+#include "updates/changesets.h"
+#include "updates/ddns.h"
+#include "tsig-op.h"
+
+/*----------------------------------------------------------------------------*/
+
+/*! \brief Maximum UDP payload with EDNS enabled. */
+static const uint16_t MAX_UDP_PAYLOAD_EDNS = 4096;
+/*! \brief Maximum UDP payload with EDNS disabled. */
+static const uint16_t MAX_UDP_PAYLOAD = 504; // 512 - 8B header
+/*! \brief Maximum size of one AXFR response packet. */
+static const uint16_t MAX_AXFR_PAYLOAD = 65535;
+/*! \brief Supported EDNS version. */
+static const uint8_t EDNS_VERSION = 0;
+/*! \brief Determines whether EDNS is enabled. */
+static const int EDNS_ENABLED = 1;
+
+/*! \brief TTL of a CNAME synthetized from a DNAME. */
+static const uint32_t SYNTH_CNAME_TTL = 0;
+
+/*! \brief Determines whether DNSSEC is enabled. */
+static const int DNSSEC_ENABLED = 1;
+
+/*! \brief Determines whether NSID is enabled. */
+static const int NSID_ENABLED = 1;
+
+/*! \brief Length of NSID option data. */
+static const uint16_t NSID_LENGTH = 6;
+/*! \brief NSID option data. */
+static const uint8_t NSID_DATA[6] = {0x46, 0x6f, 0x6f, 0x42, 0x61, 0x72};
+
+/*! \brief Internal error code to propagate need for SERVFAIL response. */
+static const int NS_ERR_SERVFAIL = -999;
+
+/*----------------------------------------------------------------------------*/
+/* Private functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Finds zone where to search for the QNAME.
+ *
+ * \note As QTYPE DS requires special handling, this function finds a zone for
+ * a direct predecessor of QNAME in such case.
+ *
+ * \param zdb Zone database where to search for the proper zone.
+ * \param qname QNAME.
+ * \param qtype QTYPE.
+ *
+ * \return Zone to which QNAME belongs (according to QTYPE), or NULL if no such
+ * zone was found.
+ */
+static const knot_zone_t *ns_get_zone_for_qname(knot_zonedb_t *zdb,
+ const knot_dname_t *qname,
+ uint16_t qtype)
+{
+ const knot_zone_t *zone;
+ /*
+ * Find a zone in which to search.
+ *
+ * In case of DS query, we strip the leftmost label when searching for
+ * the zone (but use whole qname in search for the record), as the DS
+ * records are only present in a parent zone.
+ */
+ if (qtype == KNOT_RRTYPE_DS) {
+ /*! \todo Optimize, do not deep copy dname. */
+ knot_dname_t *name = knot_dname_left_chop(qname);
+ zone = knot_zonedb_find_zone_for_name(zdb, name);
+ /* Directly discard. */
+ knot_dname_free(&name);
+ } else {
+ zone = knot_zonedb_find_zone_for_name(zdb, qname);
+ }
+
+ return zone;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Synthetizes RRSet from a wildcard RRSet using the given QNAME.
+ *
+ * The synthetized RRSet is identical to the wildcard RRSets, except that the
+ * owner name is replaced by \a qname.
+ *
+ * \param wildcard_rrset Wildcard RRSet to synthetize from.
+ * \param qname Domain name to be used as the owner of the synthetized RRset.
+ *
+ * \return The synthetized RRSet (this is a newly created RRSet, remember to
+ * free it).
+ */
+static knot_rrset_t *ns_synth_from_wildcard(
+ const knot_rrset_t *wildcard_rrset, const knot_dname_t *qname)
+{
+ dbg_ns("Synthetizing RRSet from wildcard...\n");
+
+ knot_dname_t *owner = knot_dname_deep_copy(qname);
+// printf("Copied owner ptr: %p\n", owner);
+
+ knot_rrset_t *synth_rrset = knot_rrset_new(
+ owner, knot_rrset_type(wildcard_rrset),
+ knot_rrset_class(wildcard_rrset),
+ knot_rrset_ttl(wildcard_rrset));
+
+ /* Release owner, as it's retained in rrset. */
+ knot_dname_release(owner);
+
+ if (synth_rrset == NULL) {
+ return NULL;
+ }
+
+ dbg_ns("Created RRSet header:\n");
+ knot_rrset_dump(synth_rrset, 1);
+
+ // copy all RDATA
+ const knot_rdata_t *rdata = knot_rrset_rdata(wildcard_rrset);
+ while (rdata != NULL) {
+ // we could use the RDATA from the wildcard rrset
+ // but there is no way to distinguish it when deleting
+ // temporary RRSets
+ knot_rdata_t *rdata_copy = knot_rdata_deep_copy(rdata,
+ knot_rrset_type(synth_rrset));
+ if (rdata_copy == NULL) {
+ knot_rrset_deep_free(&synth_rrset, 1, 1, 0);
+ return NULL;
+ }
+
+ dbg_ns("Copied RDATA:\n");
+ knot_rdata_dump(rdata_copy,
+ knot_rrset_type(synth_rrset), 1);
+
+ knot_rrset_add_rdata(synth_rrset, rdata_copy);
+ rdata = knot_rrset_rdata_next(wildcard_rrset, rdata);
+ }
+
+// printf("Synthetized RRSet pointer: %p\n", synth_rrset);
+ return synth_rrset;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Checks if the given RRSet is a wildcard RRSet and replaces it with
+ * a synthetized RRSet if required.
+ *
+ * \param name Domain name to be used as the owner of the possibly synthetized
+ * RRSet
+ * \param resp Response to which the synthetized RRSet should be stored (as a
+ * temporary RRSet).
+ * \param rrset RRSet to check (and possibly replace).
+ */
+static void ns_check_wildcard(const knot_dname_t *name, knot_packet_t *resp,
+ const knot_rrset_t **rrset)
+{
+ assert(name != NULL);
+ assert(resp != NULL);
+ assert(rrset != NULL);
+ assert(*rrset != NULL);
+
+ if (knot_dname_is_wildcard((*rrset)->owner)) {
+ knot_rrset_t *synth_rrset =
+ ns_synth_from_wildcard(*rrset, name);
+ dbg_ns("Synthetized RRSet:\n");
+ knot_rrset_dump(synth_rrset, 1);
+ knot_packet_add_tmp_rrset(resp, synth_rrset);
+ *rrset = synth_rrset;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adds signatures (RRSIGs) for the given RRSet to the response.
+ *
+ * This function first checks if DNSSEC is enabled and if it was requested in
+ * the response (DO bit set). If not, it does nothing and returns 0. If yes,
+ * it retrieves RRSIGs stored in the RRSet, deals with possible wildcard owner
+ * and adds the RRSIGs to response using the given function (that determines
+ * to which section of the response they will be added).
+ *
+ * \param rrset RRSet to get the RRSIGs from.
+ * \param resp Response where to add the RRSIGs.
+ * \param name Actual name to be used as owner in case of wildcard RRSet.
+ * \param add_rrset_to_resp Function for adding the RRSIG RRset to the response.
+ * \param tc Set to 1 if omitting the RRSIG RRSet should result in setting the
+ * TC bit in the response.
+ *
+ * \return KNOT_EOK
+ * \return KNOT_ENOMEM
+ * \return KNOT_ESPACE
+ */
+static int ns_add_rrsigs(const knot_rrset_t *rrset, knot_packet_t *resp,
+ const knot_dname_t *name,
+ int (*add_rrset_to_resp)(knot_packet_t *,
+ const knot_rrset_t *,
+ int, int, int),
+ int tc)
+{
+ const knot_rrset_t *rrsigs;
+
+ dbg_ns("Adding RRSIGs for RRSet, type: %s.\n",
+ knot_rrtype_to_string(knot_rrset_type(rrset)));
+
+ assert(resp != NULL);
+ assert(add_rrset_to_resp != NULL);
+
+ dbg_ns("DNSSEC requested: %d\n",
+ knot_query_dnssec_requested(knot_packet_query(resp)));
+ dbg_ns("RRSIGS: %p\n", knot_rrset_rrsigs(rrset));
+
+ if (DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp))
+ && (rrsigs = knot_rrset_rrsigs(rrset)) != NULL) {
+ if (name != NULL) {
+ ns_check_wildcard(name, resp, &rrsigs);
+ }
+ return add_rrset_to_resp(resp, rrsigs, tc, 0, 0);
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Resolves CNAME chain starting in \a node, stores all the CNAMEs in the
+ * response and updates \a node and \a qname to the last node in the
+ * chain.
+ *
+ * \param node Node (possibly) containing a CNAME RR.
+ * \param qname Searched name. Will be updated to the canonical name.
+ * \param resp Response where to add the CNAME RRs.
+ * \param add_rrset_to_resp Function for adding the CNAME RRs to the response.
+ * \param tc Set to 1 if omitting the RRSIG RRSet should result in setting the
+ * TC bit in the response.
+ */
+static void ns_follow_cname(const knot_node_t **node,
+ const knot_dname_t **qname,
+ knot_packet_t *resp,
+ int (*add_rrset_to_resp)(knot_packet_t *,
+ const knot_rrset_t *,
+ int, int, int),
+ int tc)
+{
+ dbg_ns("Resolving CNAME chain...\n");
+ const knot_rrset_t *cname_rrset;
+
+ while (*node != NULL
+ && (cname_rrset = knot_node_rrset(*node, KNOT_RRTYPE_CNAME))
+ != NULL) {
+ /* put the CNAME record to answer, but replace the possible
+ wildcard name with qname */
+
+ assert(cname_rrset != NULL);
+
+ dbg_ns("CNAME RRSet: %p, owner: %p\n", cname_rrset,
+ cname_rrset->owner);
+
+ const knot_rrset_t *rrset = cname_rrset;
+
+ // ignoring other than the first record
+ if (knot_dname_is_wildcard(knot_node_owner(*node))) {
+ /* if wildcard node, we must copy the RRSet and
+ replace its owner */
+ rrset = ns_synth_from_wildcard(cname_rrset, *qname);
+ knot_packet_add_tmp_rrset(resp, (knot_rrset_t *)rrset);
+ add_rrset_to_resp(resp, rrset, tc, 0, 0);
+ ns_add_rrsigs(cname_rrset, resp, *qname,
+ add_rrset_to_resp, tc);
+ } else {
+ add_rrset_to_resp(resp, rrset, tc, 0, 0);
+ ns_add_rrsigs(rrset, resp, *qname, add_rrset_to_resp,
+ tc);
+ }
+
+ dbg_ns("Using RRSet: %p, owner: %p\n", rrset, rrset->owner);
+
+dbg_ns_exec(
+ char *name = knot_dname_to_str(knot_rrset_owner(rrset));
+ dbg_ns("CNAME record for owner %s put to response.\n", name);
+ free(name);
+);
+
+ // get the name from the CNAME RDATA
+ const knot_dname_t *cname = knot_rdata_cname_name(
+ knot_rrset_rdata(cname_rrset));
+ dbg_ns("CNAME name from RDATA: %p\n", cname);
+ // change the node to the node of that name
+ *node = knot_dname_node(cname, 1);
+ dbg_ns("This name's node: %p\n", *node);
+// // it is not an old node and if yes, skip it
+// if (knot_node_is_old(*node)) {
+// *node = knot_node_new_node(*node);
+// }
+
+ // save the new name which should be used for replacing wildcard
+ *qname = cname;
+ };
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Retrieves RRSet(s) of given type from the given node and adds them to
+ * the response's Answer section.
+ *
+ * \param node Node where to take the RRSet from.
+ * \param name Actual searched name (used in case of wildcard RRSet(s)).
+ * \param type Type of the RRSet(s). If set to KNOT_RRTYPE_ANY, all RRSets
+ * from the node will be added to the answer.
+ * \param resp Response where to add the RRSets.
+ *
+ * \return Number of RRSets added.
+ */
+static int ns_put_answer(const knot_node_t *node, const knot_dname_t *name,
+ uint16_t type, knot_packet_t *resp)
+{
+ int added = 0;
+dbg_ns_exec(
+ char *name_str = knot_dname_to_str(node->owner);
+ dbg_ns("Putting answers from node %s.\n", name_str);
+ free(name_str);
+);
+
+ switch (type) {
+ case KNOT_RRTYPE_ANY: {
+ dbg_ns("Returning all RRTYPES.\n");
+ const knot_rrset_t **rrsets = knot_node_rrsets(node);
+ if (rrsets == NULL) {
+ break;
+ }
+ int i = 0;
+ int ret = 0;
+ const knot_rrset_t *rrset;
+ while (i < knot_node_rrset_count(node)) {
+ assert(rrsets[i] != NULL);
+ rrset = rrsets[i];
+
+ dbg_ns(" Type: %s\n",
+ knot_rrtype_to_string(knot_rrset_type(rrset)));
+
+ ns_check_wildcard(name, resp, &rrset);
+ ret = knot_response_add_rrset_answer(resp, rrset, 1,
+ 0, 0);
+ if (ret >= 0 && (added += 1)
+ && (ret = ns_add_rrsigs(rrset, resp, name,
+ knot_response_add_rrset_answer, 1))
+ >=0 ) {
+ added += 1;
+ } else {
+ free(rrsets);
+ rrsets = NULL;
+ break;
+ }
+
+ ++i;
+ }
+ if (rrsets != NULL) {
+ free(rrsets);
+ }
+ break;
+ }
+ case KNOT_RRTYPE_RRSIG: {
+ dbg_ns("Returning all RRSIGs.\n");
+ const knot_rrset_t **rrsets = knot_node_rrsets(node);
+ if (rrsets == NULL) {
+ break;
+ }
+ int i = 0;
+ int ret = 0;
+ const knot_rrset_t *rrset;
+ while (i < knot_node_rrset_count(node)) {
+ assert(rrsets[i] != NULL);
+ rrset = knot_rrset_rrsigs(rrsets[i]);
+
+ if (rrset == NULL) {
+ ++i;
+ continue;
+ }
+
+ ns_check_wildcard(name, resp, &rrset);
+ ret = knot_response_add_rrset_answer(resp, rrset, 1,
+ 0, 0);
+
+ if (ret < 0) {
+ break;
+ }
+
+ added += 1;
+ ++i;
+ }
+ free(rrsets);
+ break;
+ }
+ default: {
+ int ret = 0;
+ const knot_rrset_t *rrset = knot_node_rrset(node, type);
+ const knot_rrset_t *rrset2 = rrset;
+ if (rrset != NULL) {
+ dbg_ns("Found RRSet of type %s\n",
+ knot_rrtype_to_string(type));
+ ns_check_wildcard(name, resp, &rrset2);
+ ret = knot_response_add_rrset_answer(resp, rrset2, 1,
+ 0, 0);
+ if (ret >= 0 && (added += 1)
+ && (ret = ns_add_rrsigs(rrset, resp, name,
+ knot_response_add_rrset_answer, 1)) > 0) {
+ added += 1;
+ }
+ }
+ }
+ }
+
+ knot_response_set_rcode(resp, KNOT_RCODE_NOERROR);
+ return added;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adds RRSets to Additional section of the response.
+ *
+ * This function uses knot_rdata_get_name() to get the domain name from the
+ * RDATA of the RRSet according to its type. It also does not search for the
+ * retrieved domain name, but just uses its node field. Thus to work correctly,
+ * the zone where the RRSet is from should be adjusted using
+ * knot_zone_adjust_dnames().
+ *
+ * A and AAAA RRSets (and possible CNAMEs) for the found domain names are added.
+ *
+ * \warning Use this function only with types containing some domain name,
+ * otherwise it will crash (or behave strangely).
+ *
+ * \param resp Response where to add the Additional data.
+ * \param rrset RRSet to get the Additional data for.
+ */
+static void ns_put_additional_for_rrset(knot_packet_t *resp,
+ const knot_rrset_t *rrset)
+{
+ const knot_node_t *node = NULL;
+ const knot_rdata_t *rdata = NULL;
+ const knot_dname_t *dname = NULL;
+
+ // for all RRs in the RRset
+ rdata = knot_rrset_rdata(rrset);
+ while (rdata != NULL) {
+ dbg_ns("Getting name from RDATA, type %s..\n",
+ knot_rrtype_to_string(knot_rrset_type(rrset)));
+ dname = knot_rdata_get_name(rdata,
+ knot_rrset_type(rrset));
+ assert(dname != NULL);
+ node = knot_dname_node(dname, 1);
+// // check if the node is not old and if yes, take the new one
+// if (knot_node_is_old(node)) {
+// node = knot_node_new_node(node);
+// }
+
+ dbg_ns_detail("Node saved in RDATA dname: %p\n", node);
+
+ if (node != NULL && node->owner != dname) {
+ // the stored node should be the closest encloser
+ assert(knot_dname_is_subdomain(dname, node->owner));
+ // try the wildcard child, if any
+ node = knot_node_wildcard_child(node, 1);
+// // this should not be old node!!
+// assert(!knot_node_is_old(node));
+ }
+
+ const knot_rrset_t *rrset_add;
+
+ if (node != NULL) {
+dbg_ns_exec(
+ char *name = knot_dname_to_str(node->owner);
+ dbg_ns("Putting additional from node %s\n", name);
+ free(name);
+);
+ dbg_ns("Checking CNAMEs...\n");
+ if (knot_node_rrset(node, KNOT_RRTYPE_CNAME)
+ != NULL) {
+ dbg_ns("Found CNAME in node, following...\n");
+ const knot_dname_t *dname
+ = knot_node_owner(node);
+ ns_follow_cname(&node, &dname, resp,
+ knot_response_add_rrset_additional, 0);
+ }
+
+ // A RRSet
+ dbg_ns("A RRSets...\n");
+ rrset_add = knot_node_rrset(node, KNOT_RRTYPE_A);
+ if (rrset_add != NULL) {
+ dbg_ns("Found A RRsets.\n");
+ const knot_rrset_t *rrset_add2 = rrset_add;
+ ns_check_wildcard(dname, resp, &rrset_add2);
+ knot_response_add_rrset_additional(
+ resp, rrset_add2, 0, 1, 0);
+ ns_add_rrsigs(rrset_add, resp, dname,
+ knot_response_add_rrset_additional, 0);
+ }
+
+ // AAAA RRSet
+ dbg_ns("AAAA RRSets...\n");
+ rrset_add = knot_node_rrset(node, KNOT_RRTYPE_AAAA);
+ if (rrset_add != NULL) {
+ dbg_ns("Found AAAA RRsets.\n");
+ const knot_rrset_t *rrset_add2 = rrset_add;
+ ns_check_wildcard(dname, resp, &rrset_add2);
+ knot_response_add_rrset_additional(
+ resp, rrset_add2, 0, 1, 0);
+ ns_add_rrsigs(rrset_add, resp, dname,
+ knot_response_add_rrset_additional, 0);
+ }
+ }
+
+ assert(rrset != NULL);
+ assert(rdata != NULL);
+ rdata = knot_rrset_rdata_next(rrset, rdata);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Checks whether the given type requires additional processing.
+ *
+ * Only MX, NS and SRV types require additional processing.
+ *
+ * \param qtype Type to check.
+ *
+ * \retval <> 0 if additional processing is needed for \a qtype.
+ * \retval 0 otherwise.
+ */
+static int ns_additional_needed(uint16_t qtype)
+{
+ return (qtype == KNOT_RRTYPE_MX ||
+ qtype == KNOT_RRTYPE_NS ||
+ qtype == KNOT_RRTYPE_SRV);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adds whatever Additional RRSets are required for the response.
+ *
+ * For each RRSet in Answer and Authority sections this function checks if
+ * additional processing is needed and if yes, it puts any Additional RRSets
+ * available to the Additional section of the response.
+ *
+ * \param resp Response to process.
+ */
+static void ns_put_additional(knot_packet_t *resp)
+{
+ dbg_ns("ADDITIONAL SECTION PROCESSING\n");
+
+ const knot_rrset_t *rrset = NULL;
+
+ for (int i = 0; i < knot_packet_answer_rrset_count(resp); ++i) {
+ rrset = knot_packet_answer_rrset(resp, i);
+ assert(rrset != NULL);
+ if (ns_additional_needed(knot_rrset_type(rrset))) {
+ ns_put_additional_for_rrset(resp, rrset);
+ }
+ }
+
+ for (int i = 0; i < knot_packet_authority_rrset_count(resp); ++i) {
+ rrset = knot_packet_authority_rrset(resp, i);
+ if (ns_additional_needed(knot_rrset_type(rrset))) {
+ ns_put_additional_for_rrset(resp, rrset);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts authority NS RRSet to the Auhority section of the response.
+ *
+ * \param zone Zone to take the authority NS RRSet from.
+ * \param resp Response where to add the RRSet.
+ */
+static void ns_put_authority_ns(const knot_zone_contents_t *zone,
+ knot_packet_t *resp)
+{
+ const knot_rrset_t *ns_rrset = knot_node_rrset(
+ knot_zone_contents_apex(zone), KNOT_RRTYPE_NS);
+
+ if (ns_rrset != NULL) {
+ knot_response_add_rrset_authority(resp, ns_rrset, 0, 1, 0);
+ ns_add_rrsigs(ns_rrset, resp, knot_node_owner(
+ knot_zone_contents_apex(zone)),
+ knot_response_add_rrset_authority, 1);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts SOA RRSet to the Auhority section of the response.
+ *
+ * \param zone Zone to take the SOA RRSet from.
+ * \param resp Response where to add the RRSet.
+ */
+static void ns_put_authority_soa(const knot_zone_contents_t *zone,
+ knot_packet_t *resp)
+{
+ const knot_rrset_t *soa_rrset = knot_node_rrset(
+ knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
+ assert(soa_rrset != NULL);
+
+ knot_response_add_rrset_authority(resp, soa_rrset, 0, 0, 0);
+ ns_add_rrsigs(soa_rrset, resp,
+ knot_node_owner(knot_zone_contents_apex(zone)),
+ knot_response_add_rrset_authority, 1);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates a 'next closer name' to the given domain name.
+ *
+ * For definition of 'next closer name', see RFC5155, Page 6.
+ *
+ * \param closest_encloser Closest encloser of \a name.
+ * \param name Domain name to create the 'next closer' name to.
+ *
+ * \return 'Next closer name' to the given domain name or NULL if an error
+ * occured.
+ */
+static knot_dname_t *ns_next_closer(const knot_dname_t *closest_encloser,
+ const knot_dname_t *name)
+{
+ int ce_labels = knot_dname_label_count(closest_encloser);
+ int qname_labels = knot_dname_label_count(name);
+
+ assert(ce_labels < qname_labels);
+
+ // the common labels should match
+ assert(knot_dname_matched_labels(closest_encloser, name)
+ == ce_labels);
+
+ // chop some labels from the qname
+ knot_dname_t *next_closer = knot_dname_deep_copy(name);
+ if (next_closer == NULL) {
+ return NULL;
+ }
+
+ for (int i = 0; i < (qname_labels - ce_labels - 1); ++i) {
+ knot_dname_left_chop_no_copy(next_closer);
+ }
+
+ return next_closer;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adds NSEC3 RRSet (together with corresponding RRSIGs) from the given
+ * node into the response.
+ *
+ * \param node Node to get the NSEC3 RRSet from.
+ * \param resp Response where to add the RRSets.
+ */
+static void ns_put_nsec3_from_node(const knot_node_t *node,
+ knot_packet_t *resp)
+{
+ assert(DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp)));
+
+ const knot_rrset_t *rrset = knot_node_rrset(node,
+ KNOT_RRTYPE_NSEC3);
+ assert(rrset != NULL);
+
+ int res = knot_response_add_rrset_authority(resp, rrset, 1, 1, 0);
+ // add RRSIG for the RRSet
+ if (res == 0 && (rrset = knot_rrset_rrsigs(rrset)) != NULL) {
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Finds and adds NSEC3 covering the given domain name (and their
+ * associated RRSIGs) to the response.
+ *
+ * \param zone Zone used for answering.
+ * \param name Domain name to cover.
+ * \param resp Response where to add the RRSets.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL if a runtime collision occured. The server should
+ * respond with SERVFAIL in such case.
+ */
+static int ns_put_covering_nsec3(const knot_zone_contents_t *zone,
+ const knot_dname_t *name,
+ knot_packet_t *resp)
+{
+ const knot_node_t *prev, *node;
+ /*! \todo Check version. */
+ int match = knot_zone_contents_find_nsec3_for_name(zone, name,
+ &node, &prev, 1);
+ assert(match >= 0);
+ node = knot_node_current(node);
+ prev = knot_node_current(prev);
+
+ if (match == KNOT_ZONE_NAME_FOUND){
+ // run-time collision => SERVFAIL
+ return KNOT_EOK;
+ }
+
+// // check if the prev node is not old and if yes, take the new one
+// if (knot_node_is_old(prev)) {
+// prev = knot_node_new_node(prev);
+// assert(prev != NULL);
+// }
+
+dbg_ns_exec(
+ char *name = knot_dname_to_str(prev->owner);
+ dbg_ns("Covering NSEC3 node: %s\n", name);
+ free(name);
+);
+
+ ns_put_nsec3_from_node(prev, resp);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adds NSEC3s comprising the 'closest encloser proof' for the given
+ * (non-existent) domain name (and their associated RRSIGs) to the
+ * response.
+ *
+ * For definition of 'closest encloser proof', see RFC5155, section 7.2.1,
+ * Page 18.
+ *
+ * \note This function does not check if DNSSEC is enabled, nor if it is
+ * requested by the query.
+ *
+ * \param zone Zone used for answering.
+ * \param closest_encloser Closest encloser of \a qname in the zone.
+ * \param qname Searched (non-existent) name.
+ * \param resp Response where to add the NSEC3s.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_put_nsec3_closest_encloser_proof(
+ const knot_zone_contents_t *zone,
+ const knot_node_t **closest_encloser,
+ const knot_dname_t *qname,
+ knot_packet_t *resp)
+{
+ assert(zone != NULL);
+ assert(closest_encloser != NULL);
+ assert(*closest_encloser != NULL);
+ assert(qname != NULL);
+ assert(resp != NULL);
+
+ if (knot_zone_contents_nsec3params(zone) == NULL) {
+dbg_ns_exec(
+ char *name = knot_dname_to_str(knot_node_owner(
+ knot_zone_contents_apex(zone)));
+ dbg_ns("No NSEC3PARAM found in zone %s.\n", name);
+ free(name);
+);
+ return KNOT_EOK;
+ }
+
+dbg_ns_exec(
+ char *name = knot_dname_to_str(knot_node_owner(*closest_encloser));
+ dbg_ns("Closest encloser: %s\n", name);
+ free(name);
+);
+
+ /*
+ * 1) NSEC3 that matches closest provable encloser.
+ */
+ const knot_node_t *nsec3_node = NULL;
+ const knot_dname_t *next_closer = NULL;
+ while ((nsec3_node = knot_node_nsec3_node((*closest_encloser), 1))
+ == NULL) {
+ next_closer = knot_node_owner((*closest_encloser));
+ *closest_encloser = knot_node_parent(*closest_encloser, 1);
+ if (*closest_encloser == NULL) {
+ // there are no NSEC3s to add
+ return KNOT_EOK;
+ }
+ }
+
+ assert(nsec3_node != NULL);
+
+dbg_ns_exec(
+ char *name = knot_dname_to_str(nsec3_node->owner);
+ dbg_ns("NSEC3 node: %s\n", name);
+ free(name);
+ name = knot_dname_to_str((*closest_encloser)->owner);
+ dbg_ns("Closest provable encloser: %s\n", name);
+ free(name);
+ if (next_closer != NULL) {
+ name = knot_dname_to_str(next_closer);
+ dbg_ns("Next closer name: %s\n", name);
+ free(name);
+ } else {
+ dbg_ns("Next closer name: none\n");
+ }
+);
+
+ ns_put_nsec3_from_node(nsec3_node, resp);
+
+ /*
+ * 2) NSEC3 that covers the "next closer" name.
+ */
+ int ret = 0;
+ if (next_closer == NULL) {
+ // create the "next closer" name by appending from qname
+ next_closer = ns_next_closer(
+ knot_node_owner(*closest_encloser), qname);
+
+ if (next_closer == NULL) {
+ return NS_ERR_SERVFAIL;
+ }
+dbg_ns_exec(
+ char *name = knot_dname_to_str(next_closer);
+ dbg_ns("Next closer name: %s\n", name);
+ free(name);
+);
+ ret = ns_put_covering_nsec3(zone, next_closer, resp);
+
+ // the cast is ugly, but no better way around it
+ knot_dname_release((knot_dname_t *)next_closer);
+ } else {
+ ret = ns_put_covering_nsec3(zone, next_closer, resp);
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates a name of a wildcard child of \a name.
+ *
+ * \param name Domain name to get the wildcard child name of.
+ *
+ * \return Wildcard child name or NULL if an error occured.
+ */
+static knot_dname_t *ns_wildcard_child_name(const knot_dname_t *name)
+{
+ assert(name != NULL);
+
+ knot_dname_t *wildcard = knot_dname_new_from_str("*", 1, NULL);
+ if (wildcard == NULL) {
+ return NULL;
+ }
+
+ if (knot_dname_cat(wildcard, name) == NULL) {
+ /* Directly discard dname. */
+ knot_dname_free(&wildcard);
+ return NULL;
+ }
+
+dbg_ns_exec(
+ char *name = knot_dname_to_str(wildcard);
+ dbg_ns("Wildcard: %s\n", name);
+ free(name);
+);
+ return wildcard;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSEC3s covering the non-existent wildcard child of a node
+ * (and their associated RRSIGs) into the response.
+ *
+ * \note This function does not check if DNSSEC is enabled, nor if it is
+ * requested by the query.
+ *
+ * \param zone Zone used for answering.
+ * \param node Node whose non-existent wildcard child should be covered.
+ * \param resp Response where to add the NSEC3s.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_put_nsec3_no_wildcard_child(const knot_zone_contents_t *zone,
+ const knot_node_t *node,
+ knot_packet_t *resp)
+{
+ assert(node != NULL);
+ assert(resp != NULL);
+ assert(node->owner != NULL);
+
+ int ret = 0;
+ knot_dname_t *wildcard = ns_wildcard_child_name(node->owner);
+ if (wildcard == NULL) {
+ ret = NS_ERR_SERVFAIL;
+ } else {
+ ret = ns_put_covering_nsec3(zone, wildcard, resp);
+
+ /* Directly discard wildcard. */
+ knot_dname_free(&wildcard);
+ }
+
+ return ret;
+}
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSECs or NSEC3s for NODATA error (and their associated RRSIGs)
+ * to the response.
+ *
+ * \note This function first checks if DNSSEC is enabled and requested by the
+ * query.
+ * \note Note that for each zone there are either NSEC or NSEC3 records used.
+ *
+ * \param node Node which generated the NODATA response (i.e. not containing
+ * RRSets of the requested type).
+ * \param resp Response where to add the NSECs or NSEC3s.
+ */
+static void ns_put_nsec_nsec3_nodata(const knot_node_t *node,
+ knot_packet_t *resp)
+{
+ if (!DNSSEC_ENABLED ||
+ !knot_query_dnssec_requested(knot_packet_query(resp))) {
+ return;
+ }
+
+ const knot_node_t *nsec3_node = knot_node_nsec3_node(node, 1);
+ const knot_rrset_t *rrset = NULL;
+ if ((rrset = knot_node_rrset(node, KNOT_RRTYPE_NSEC)) != NULL
+ || (nsec3_node != NULL && (rrset =
+ knot_node_rrset(nsec3_node, KNOT_RRTYPE_NSEC3)) != NULL)) {
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+ // add RRSIG for the RRSet
+ if ((rrset = knot_rrset_rrsigs(rrset)) != NULL) {
+ knot_response_add_rrset_authority(resp, rrset, 1,
+ 0, 0);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSECs for NXDOMAIN error to the response.
+ *
+ * \note This function does not check if DNSSEC is enabled, nor if it is
+ * requested by the query.
+ *
+ * \param qname QNAME which generated the NXDOMAIN error (i.e. not found in the
+ * zone).
+ * \param zone Zone used for answering.
+ * \param previous Previous node to \a qname in the zone. May also be NULL. In
+ * such case the function finds the previous node in the zone.
+ * \param closest_encloser Closest encloser of \a qname. Must not be NULL.
+ * \param resp Response where to put the NSECs.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_put_nsec_nxdomain(const knot_dname_t *qname,
+ const knot_zone_contents_t *zone,
+ const knot_node_t *previous,
+ const knot_node_t *closest_encloser,
+ knot_packet_t *resp)
+{
+ const knot_rrset_t *rrset = NULL;
+
+ // check if we have previous; if not, find one using the tree
+ if (previous == NULL) {
+ /*! \todo Check version. */
+ previous = knot_zone_contents_find_previous(zone, qname);
+
+ while (!knot_node_is_auth(previous)) {
+ previous = knot_node_previous(previous, 1);
+ }
+
+ previous = knot_node_current(previous);
+ assert(previous != NULL);
+ }
+
+ char *name = knot_dname_to_str(previous->owner);
+ dbg_ns("Previous node: %s\n", name);
+ free(name);
+
+ // 1) NSEC proving that there is no node with the searched name
+ rrset = knot_node_rrset(previous, KNOT_RRTYPE_NSEC);
+ if (rrset == NULL) {
+ // no NSEC records
+ //return NS_ERR_SERVFAIL;
+ return KNOT_EOK;
+
+ }
+
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+ rrset = knot_rrset_rrsigs(rrset);
+ assert(rrset != NULL);
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+
+ // 2) NSEC proving that there is no wildcard covering the name
+ // this is only different from 1) if the wildcard would be
+ // before 'previous' in canonical order, i.e. we can
+ // search for previous until we find name lesser than wildcard
+ assert(closest_encloser != NULL);
+
+ knot_dname_t *wildcard =
+ ns_wildcard_child_name(closest_encloser->owner);
+ if (wildcard == NULL) {
+ return NS_ERR_SERVFAIL;
+ }
+
+ const knot_node_t *prev_new = previous;
+
+ while (knot_dname_compare(knot_node_owner(prev_new),
+ wildcard) > 0) {
+ dbg_ns("Previous node: %s\n",
+ knot_dname_to_str(knot_node_owner(prev_new)));
+ assert(prev_new != knot_zone_contents_apex(zone));
+ prev_new = knot_node_previous(prev_new, 1);
+ }
+ assert(knot_dname_compare(knot_node_owner(prev_new),
+ wildcard) < 0);
+
+ dbg_ns("Previous node: %s\n",
+ knot_dname_to_str(knot_node_owner(prev_new)));
+
+ /* Directly discard dname. */
+ knot_dname_free(&wildcard);
+
+ if (prev_new != previous) {
+ rrset = knot_node_rrset(prev_new, KNOT_RRTYPE_NSEC);
+ assert(rrset != NULL);
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+ rrset = knot_rrset_rrsigs(rrset);
+ assert(rrset != NULL);
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSEC3s for NXDOMAIN error to the response.
+ *
+ * \note This function does not check if DNSSEC is enabled, nor if it is
+ * requested by the query.
+ *
+ * \param zone Zone used for answering.
+ * \param closest_encloser Closest encloser of \a qname.
+ * \param qname Domain name which generated the NXDOMAIN error (i.e. not found
+ * in the zone.
+ * \param resp Response where to put the NSEC3s.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_put_nsec3_nxdomain(const knot_zone_contents_t *zone,
+ const knot_node_t *closest_encloser,
+ const knot_dname_t *qname,
+ knot_packet_t *resp)
+{
+ // 1) Closest encloser proof
+ dbg_ns("Putting closest encloser proof.\n");
+ int ret = ns_put_nsec3_closest_encloser_proof(zone, &closest_encloser,
+ qname, resp);
+ // 2) NSEC3 covering non-existent wildcard
+ if (ret == KNOT_EOK && closest_encloser != NULL) {
+ dbg_ns("Putting NSEC3 for no wildcard child of closest "
+ "encloser.\n");
+ ret = ns_put_nsec3_no_wildcard_child(zone, closest_encloser,
+ resp);
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSECs or NSEC3s for the NXDOMAIN error to the response.
+ *
+ * \note This function first checks if DNSSEC is enabled and requested by the
+ * query.
+ * \note Note that for each zone there are either NSEC or NSEC3 records used.
+ *
+ * \param zone Zone used for answering.
+ * \param previous Previous node to \a qname in the zone. May also be NULL. In
+ * such case the function finds the previous node in the zone.
+ * \param closest_encloser Closest encloser of \a qname. Must not be NULL.
+ * \param qname QNAME which generated the NXDOMAIN error (i.e. not found in the
+ * zone).
+ * \param resp Response where to put the NSECs.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_put_nsec_nsec3_nxdomain(const knot_zone_contents_t *zone,
+ const knot_node_t *previous,
+ const knot_node_t *closest_encloser,
+ const knot_dname_t *qname,
+ knot_packet_t *resp)
+{
+ int ret = 0;
+ if (DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp))) {
+ if (knot_zone_contents_nsec3_enabled(zone)) {
+ ret = ns_put_nsec3_nxdomain(zone, closest_encloser,
+ qname, resp);
+ } else {
+ ret = ns_put_nsec_nxdomain(qname, zone, previous,
+ closest_encloser, resp);
+ }
+ }
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSEC3s for wildcard answer into the response.
+ *
+ * \note This function does not check if DNSSEC is enabled, nor if it is
+ * requested by the query.
+ *
+ * \param zone Zone used for answering.
+ * \param closest_encloser Closest encloser of \a qname in the zone. In this
+ * case it is the parent of the source of synthesis.
+ * \param qname Domain name covered by the wildcard used for answering the
+ * query.
+ * \param resp Response to put the NSEC3s into.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_put_nsec3_wildcard(const knot_zone_contents_t *zone,
+ const knot_node_t *closest_encloser,
+ const knot_dname_t *qname,
+ knot_packet_t *resp)
+{
+ assert(closest_encloser != NULL);
+ assert(qname != NULL);
+ assert(resp != NULL);
+ assert(DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp)));
+
+ if (!knot_zone_contents_nsec3_enabled(zone)) {
+ return KNOT_EOK;
+ }
+
+ /*
+ * NSEC3 that covers the "next closer" name.
+ */
+ // create the "next closer" name by appending from qname
+ dbg_ns("Finding next closer name for wildcard NSEC3.\n");
+ knot_dname_t *next_closer =
+ ns_next_closer(closest_encloser->owner, qname);
+
+ if (next_closer == NULL) {
+ return NS_ERR_SERVFAIL;
+ }
+dbg_ns_exec(
+ char *name = knot_dname_to_str(next_closer);
+ dbg_ns("Next closer name: %s\n", name);
+ free(name);
+);
+ int ret = ns_put_covering_nsec3(zone, next_closer, resp);
+
+
+ /* Duplicate from ns_next_close(), safe to discard. */
+ knot_dname_release(next_closer);
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSECs for wildcard answer into the response.
+ *
+ * \note This function does not check if DNSSEC is enabled, nor if it is
+ * requested by the query.
+ *
+ * \param zone Zone used for answering.
+ * \param qname Domain name covered by the wildcard used for answering the
+ * query.
+ * \param previous Previous node of \a qname in canonical order.
+ * \param resp Response to put the NSEC3s into.
+ */
+static void ns_put_nsec_wildcard(const knot_zone_contents_t *zone,
+ const knot_dname_t *qname,
+ const knot_node_t *previous,
+ knot_packet_t *resp)
+{
+ assert(DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp)));
+
+ // check if we have previous; if not, find one using the tree
+ if (previous == NULL) {
+ previous = knot_zone_contents_find_previous(zone, qname);
+
+ while (!knot_node_is_auth(previous)) {
+ previous = knot_node_previous(previous, 1);
+ }
+
+ previous = knot_node_current(previous);
+ assert(previous != NULL);
+ }
+
+ const knot_rrset_t *rrset =
+ knot_node_rrset(previous, KNOT_RRTYPE_NSEC);
+ if (rrset != NULL) {
+ // NSEC proving that there is no node with the searched name
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+ rrset = knot_rrset_rrsigs(rrset);
+ assert(rrset != NULL);
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSECs or NSEC3s for wildcard NODATA answer into the response.
+ *
+ * \note This function first checks if DNSSEC is enabled and requested by the
+ * query.
+ *
+ * \param node Node used for answering.
+ * \param closest_encloser Closest encloser of \a qname in the zone.
+ * \param previous Previous node of \a qname in canonical order.
+ * \param zone Zone used for answering.
+ * \param qname Actual searched domain name.
+ * \param resp Response where to put the NSECs and NSEC3s.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_put_nsec_nsec3_wildcard_nodata(const knot_node_t *node,
+ const knot_node_t *closest_encloser,
+ const knot_node_t *previous,
+ const knot_zone_contents_t *zone,
+ const knot_dname_t *qname,
+ knot_packet_t *resp)
+{
+ int ret = KNOT_EOK;
+ if (DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp))) {
+ if (knot_zone_contents_nsec3_enabled(zone)) {
+ ret = ns_put_nsec3_closest_encloser_proof(zone,
+ &closest_encloser,
+ qname, resp);
+
+ const knot_node_t *nsec3_node;
+ if (ret == KNOT_EOK
+ && (nsec3_node = knot_node_nsec3_node(node, 1))
+ != NULL) {
+ ns_put_nsec3_from_node(nsec3_node, resp);
+ }
+ } else {
+ ns_put_nsec_wildcard(zone, qname, previous, resp);
+ }
+ }
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Puts NSECs or NSEC3s for wildcard answer into the response.
+ *
+ * \note This function first checks if DNSSEC is enabled and requested by the
+ * query and if the node's owner is a wildcard.
+ *
+ * \param node Node used for answering.
+ * \param closest_encloser Closest encloser of \a qname in the zone.
+ * \param previous Previous node of \a qname in canonical order.
+ * \param zone Zone used for answering.
+ * \param qname Actual searched domain name.
+ * \param resp Response where to put the NSECs and NSEC3s.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node,
+ const knot_node_t *closest_encloser,
+ const knot_node_t *previous,
+ const knot_zone_contents_t *zone,
+ const knot_dname_t *qname,
+ knot_packet_t *resp)
+{
+ int r = KNOT_EOK;
+ if (DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp))
+ && knot_dname_is_wildcard(knot_node_owner(node))) {
+ if (knot_zone_contents_nsec3_enabled(zone)) {
+ r = ns_put_nsec3_wildcard(zone, closest_encloser, qname,
+ resp);
+ } else {
+ ns_put_nsec_wildcard(zone, qname, previous, resp);
+ }
+ }
+ return r;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates a referral response.
+ *
+ * This function puts the delegation NS RRSet to the Authority section of the
+ * response, possibly adds DS and their associated RRSIGs (if DNSSEC is enabled
+ * and requested by the query) and adds any available additional data (A and
+ * AAAA RRSets for the names in the NS RRs) with their associated RRSIGs
+ * to the Additional section.
+ *
+ * \param node Delegation point node.
+ * \param zone Parent zone (the one from which the response is generated).
+ * \param qname Searched name (which caused the referral).
+ * \param resp Response.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static inline int ns_referral(const knot_node_t *node,
+ const knot_zone_contents_t *zone,
+ const knot_dname_t *qname,
+ knot_packet_t *resp)
+{
+ dbg_ns("Referral response.\n");
+
+ while (!knot_node_is_deleg_point(node)) {
+ assert(knot_node_parent(node, 1) != NULL);
+ node = knot_node_parent(node, 1);
+ }
+
+ const knot_rrset_t *rrset = knot_node_rrset(node, KNOT_RRTYPE_NS);
+ assert(rrset != NULL);
+
+ // TODO: wildcards??
+ //ns_check_wildcard(name, resp, &rrset);
+
+ knot_response_add_rrset_authority(resp, rrset, 1, 0, 0);
+ ns_add_rrsigs(rrset, resp, node->owner,
+ knot_response_add_rrset_authority, 1);
+
+ int ret = KNOT_EOK;
+ // add DS records
+ dbg_ns("DNSSEC requested: %d\n",
+ knot_query_dnssec_requested(knot_packet_query(resp)));
+ dbg_ns("DS records: %p\n", knot_node_rrset(node, KNOT_RRTYPE_DS));
+ if (DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp))) {
+ rrset = knot_node_rrset(node, KNOT_RRTYPE_DS);
+ if (rrset != NULL) {
+ knot_response_add_rrset_authority(resp, rrset, 1, 0,
+ 0);
+ ns_add_rrsigs(rrset, resp, node->owner,
+ knot_response_add_rrset_authority, 1);
+ } else {
+ // no DS, add NSEC3 or NSEC
+ // if NSEC3 enabled, search for NSEC3
+ if (knot_zone_contents_nsec3_enabled(zone)) {
+ const knot_node_t *nsec3_node =
+ knot_node_nsec3_node(node, 1);
+ dbg_ns("There is no DS, putting NSEC3s...\n");
+ if (nsec3_node != NULL) {
+ dbg_ns("Putting NSEC3s from the node.\n");
+ ns_put_nsec3_from_node(nsec3_node, resp);
+ } else {
+ dbg_ns("Putting Opt-Out NSEC3s.\n");
+ // no NSEC3 (probably Opt-Out)
+ // TODO: check if the zone is Opt-Out
+ ret = ns_put_nsec3_closest_encloser_proof(zone,
+ &node, qname, resp);
+ }
+ } else {
+ const knot_rrset_t *nsec = knot_node_rrset(
+ node, KNOT_RRTYPE_NSEC);
+ if (nsec) {
+ /*! \todo Check return value? */
+ knot_response_add_rrset_authority(
+ resp, nsec, 1, 1, 0);
+ if ((nsec = knot_rrset_rrsigs(nsec)) != NULL) {
+ knot_response_add_rrset_authority(resp, nsec, 1,
+ 1, 0);
+ }
+ }
+ }
+ }
+ }
+
+ if (ret == KNOT_EOK) {
+ ns_put_additional(resp);
+ knot_response_set_rcode(resp, KNOT_RCODE_NOERROR);
+ }
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Tries to answer the query from the given node.
+ *
+ * Tries to put RRSets of requested type (\a qtype) to the Answer section of the
+ * response. If successful, it also adds authority NS RRSet to the Authority
+ * section and it may add NSEC or NSEC3s in case of a wildcard answer (\a node
+ * is a wildcard node). If not successful (there are no such RRSets), it adds
+ * the SOA record to the Authority section and may add NSEC or NSEC3s according
+ * to the type of the response (NXDOMAIN if \a node is an empty non-terminal,
+ * NODATA if it is a regular node). It also adds any additional data that may
+ * be required.
+ *
+ * \param node Node to answer from.
+ * \param closest_encloser Closest encloser of \a qname in the zone.
+ * \param previous Previous domain name of \a qname in canonical order.
+ * \param zone Zone used for answering.
+ * \param qname Searched domain name.
+ * \param qtype Searched RR type.
+ * \param resp Response.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_answer_from_node(const knot_node_t *node,
+ const knot_node_t *closest_encloser,
+ const knot_node_t *previous,
+ const knot_zone_contents_t *zone,
+ const knot_dname_t *qname, uint16_t qtype,
+ knot_packet_t *resp)
+{
+ dbg_ns("Putting answers from found node to the response...\n");
+ int answers = ns_put_answer(node, qname, qtype, resp);
+
+ int ret = KNOT_EOK;
+ if (answers == 0) { // if NODATA response, put SOA
+ if (knot_node_rrset_count(node) == 0
+ && !knot_zone_contents_nsec3_enabled(zone)) {
+ // node is an empty non-terminal => NSEC for NXDOMAIN
+ //assert(knot_node_rrset_count(closest_encloser) > 0);
+ dbg_ns("Adding NSEC/NSEC3 for NXDOMAIN.\n");
+ ret = ns_put_nsec_nsec3_nxdomain(zone,
+ knot_node_previous(node, 1), closest_encloser,
+ qname, resp);
+ } else {
+ dbg_ns("Adding NSEC/NSEC3 for NODATA.\n");
+ ns_put_nsec_nsec3_nodata(node, resp);
+ if (knot_dname_is_wildcard(node->owner)) {
+ dbg_ns("Putting NSEC/NSEC3 for wildcard"
+ " NODATA\n");
+ ret = ns_put_nsec_nsec3_wildcard_nodata(node,
+ closest_encloser, previous, zone, qname,
+ resp);
+ }
+ }
+ ns_put_authority_soa(zone, resp);
+ } else { // else put authority NS
+ // if wildcard answer, add NSEC / NSEC3
+ dbg_ns("Adding NSEC/NSEC3 for wildcard answer.\n");
+ ret = ns_put_nsec_nsec3_wildcard_answer(node, closest_encloser,
+ previous, zone, qname, resp);
+ ns_put_authority_ns(zone, resp);
+ }
+
+ if (ret == KNOT_EOK) {
+ ns_put_additional(resp);
+ }
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Synthetizes a CNAME RR from a DNAME.
+ *
+ * \param dname_rrset DNAME RRSet to synthetize from (only the first RR is
+ * used).
+ * \param qname Name to be used as the owner name of the synthetized CNAME.
+ *
+ * \return Synthetized CNAME RRset (this is a newly created RRSet, remember to
+ * free it).
+ */
+static knot_rrset_t *ns_cname_from_dname(const knot_rrset_t *dname_rrset,
+ const knot_dname_t *qname)
+{
+ dbg_ns("Synthetizing CNAME from DNAME...\n");
+
+ // create new CNAME RRSet
+
+ knot_dname_t *owner = knot_dname_deep_copy(qname);
+ if (owner == NULL) {
+ return NULL;
+ }
+
+ knot_rrset_t *cname_rrset = knot_rrset_new(
+ owner, KNOT_RRTYPE_CNAME, KNOT_CLASS_IN, SYNTH_CNAME_TTL);
+
+ /* Release owner, as it's retained in rrset. */
+ knot_dname_release(owner);
+
+ if (cname_rrset == NULL) {
+ return NULL;
+ }
+
+ // replace last labels of qname with DNAME
+ knot_dname_t *cname = knot_dname_replace_suffix(qname,
+ knot_dname_size(knot_rrset_owner(dname_rrset)),
+ knot_rdata_get_item(knot_rrset_rdata(dname_rrset), 0)->dname);
+dbg_ns_exec(
+ char *name = knot_dname_to_str(cname);
+ dbg_ns("CNAME canonical name: %s.\n", name);
+ free(name);
+);
+ knot_rdata_t *cname_rdata = knot_rdata_new();
+ knot_rdata_item_t cname_rdata_item;
+ cname_rdata_item.dname = cname;
+ knot_rdata_set_items(cname_rdata, &cname_rdata_item, 1);
+
+ knot_rrset_add_rdata(cname_rrset, cname_rdata);
+
+ return cname_rrset;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Checks if the name created by replacing the owner of \a dname_rrset
+ * in the \a qname by the DNAME's target would be longer than allowed.
+ *
+ * \param dname_rrset DNAME RRSet to be used for the check.
+ * \param qname Name whose part is to be replaced.
+ *
+ * \retval <>0 if the created domain name would be too long.
+ * \retval 0 otherwise.
+ */
+static int ns_dname_is_too_long(const knot_rrset_t *dname_rrset,
+ const knot_dname_t *qname)
+{
+ // TODO: add function for getting DNAME target
+ if (knot_dname_label_count(qname)
+ - knot_dname_label_count(knot_rrset_owner(dname_rrset))
+ + knot_dname_label_count(knot_rdata_get_item(
+ knot_rrset_rdata(dname_rrset), 0)->dname)
+ > KNOT_MAX_DNAME_LENGTH) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief DNAME processing.
+ *
+ * This function adds the DNAME RRSet (and possibly its associated RRSIGs to the
+ * Answer section of the response, synthetizes CNAME record from the DNAME and
+ * adds it there too. It also stores the synthetized CNAME in the temporary
+ * RRSets of the response.
+ *
+ * \param dname_rrset DNAME RRSet to use.
+ * \param qname Searched name.
+ * \param resp Response.
+ */
+static void ns_process_dname(const knot_rrset_t *dname_rrset,
+ const knot_dname_t *qname,
+ knot_packet_t *resp)
+{
+dbg_ns_exec(
+ char *name = knot_dname_to_str(knot_rrset_owner(dname_rrset));
+ dbg_ns("Processing DNAME for owner %s...\n", name);
+ free(name);
+);
+ // TODO: check the number of RRs in the RRSet??
+
+ // put the DNAME RRSet into the answer
+ knot_response_add_rrset_answer(resp, dname_rrset, 1, 0, 0);
+ ns_add_rrsigs(dname_rrset, resp, qname,
+ knot_response_add_rrset_answer, 1);
+
+ if (ns_dname_is_too_long(dname_rrset, qname)) {
+ knot_response_set_rcode(resp, KNOT_RCODE_YXDOMAIN);
+ return;
+ }
+
+ // synthetize CNAME (no way to tell that client supports DNAME)
+ knot_rrset_t *synth_cname = ns_cname_from_dname(dname_rrset, qname);
+ // add the synthetized RRSet to the Answer
+ knot_response_add_rrset_answer(resp, synth_cname, 1, 0, 0);
+
+ // no RRSIGs for this RRSet
+
+ // add the synthetized RRSet into list of temporary RRSets of response
+ knot_packet_add_tmp_rrset(resp, synth_cname);
+
+ // do not search for the name in new zone (out-of-bailiwick)
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adds DNSKEY RRSet from the apex of a zone to the response.
+ *
+ * \param apex Zone apex node.
+ * \param resp Response.
+ */
+static void ns_add_dnskey(const knot_node_t *apex, knot_packet_t *resp)
+{
+ const knot_rrset_t *rrset =
+ knot_node_rrset(apex, KNOT_RRTYPE_DNSKEY);
+ if (rrset != NULL) {
+ knot_response_add_rrset_additional(resp, rrset, 0, 0, 0);
+ ns_add_rrsigs(rrset, resp, apex->owner,
+ knot_response_add_rrset_additional, 0);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Answers the query from the given zone.
+ *
+ * This function performs the actual answering logic.
+ *
+ * \param zone Zone to use for answering.
+ * \param qname QNAME from the query.
+ * \param qtype QTYPE from the query.
+ * \param resp Response to fill in.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ *
+ * \todo Describe the answering logic in detail.
+ */
+static int ns_answer_from_zone(const knot_zone_contents_t *zone,
+ const knot_dname_t *qname, uint16_t qtype,
+ knot_packet_t *resp)
+{
+ const knot_node_t *node = NULL, *closest_encloser = NULL,
+ *previous = NULL;
+ int cname = 0, auth_soa = 0, ret = 0, find_ret = 0;
+
+search:
+#ifdef USE_HASH_TABLE
+ /*! \todo Check version. */
+ find_ret = knot_zone_contents_find_dname_hash(zone, qname, &node,
+ &closest_encloser);
+// node = knot_node_current(node);
+// closest_encloser = knot_node_current(closest_encloser);
+#else
+ /*! \todo Check version. */
+ find_ret = knot_zone_contents_find_dname(zone, qname, &node,
+ &closest_encloser, &previous);
+ node = knot_node_current(node);
+ closest_encloser = knot_node_current(closest_encloser);
+ previous = knot_node_current(previous);
+#endif
+ if (find_ret == KNOT_EBADARG) {
+ return NS_ERR_SERVFAIL;
+ }
+
+dbg_ns_exec(
+ char *name;
+ if (node) {
+ name = knot_dname_to_str(node->owner);
+ dbg_ns("zone_find_dname() returned node %s ", name);
+ free(name);
+ } else {
+ dbg_ns("zone_find_dname() returned no node,");
+ }
+
+ if (closest_encloser != NULL) {
+ name = knot_dname_to_str(closest_encloser->owner);
+ dbg_ns(" closest encloser %s.\n", name);
+ free(name);
+ } else {
+ dbg_ns(" closest encloser (nil).\n");
+ }
+ if (previous != NULL) {
+ name = knot_dname_to_str(previous->owner);
+ dbg_ns(" and previous node: %s.\n", name);
+ free(name);
+ } else {
+ dbg_ns(" and previous node: (nil).\n");
+ }
+);
+ if (find_ret == KNOT_EBADZONE) {
+ // possible only if we followed cname
+ assert(cname != 0);
+ knot_response_set_rcode(resp, KNOT_RCODE_NOERROR);
+ auth_soa = 1;
+ knot_response_set_aa(resp);
+ goto finalize;
+ }
+
+have_node:
+ dbg_ns("Closest encloser is deleg. point? %s\n",
+ (knot_node_is_deleg_point(closest_encloser)) ? "yes" : "no");
+
+ dbg_ns("Closest encloser is non authoritative? %s\n",
+ (knot_node_is_non_auth(closest_encloser)) ? "yes" : "no");
+
+ if (knot_node_is_deleg_point(closest_encloser)
+ || knot_node_is_non_auth(closest_encloser)) {
+ ret = ns_referral(closest_encloser, zone, qname, resp);
+ goto finalize;
+ }
+
+ if (find_ret == KNOT_ZONE_NAME_NOT_FOUND) {
+ // DNAME?
+ const knot_rrset_t *dname_rrset = knot_node_rrset(
+ closest_encloser, KNOT_RRTYPE_DNAME);
+ if (dname_rrset != NULL) {
+ ns_process_dname(dname_rrset, qname, resp);
+ auth_soa = 1;
+ knot_response_set_aa(resp);
+ goto finalize;
+ }
+ // else check for a wildcard child
+ const knot_node_t *wildcard_node =
+ knot_node_wildcard_child(closest_encloser, 1);
+
+ if (wildcard_node == NULL) {
+ dbg_ns("No wildcard node. (cname: %d)\n",
+ cname);
+ auth_soa = 1;
+ if (cname == 0) {
+ dbg_ns("Setting NXDOMAIN RCODE.\n");
+ // return NXDOMAIN
+ knot_response_set_rcode(resp,
+ KNOT_RCODE_NXDOMAIN);
+ if (ns_put_nsec_nsec3_nxdomain(zone, previous,
+ closest_encloser, qname, resp) != 0) {
+ return NS_ERR_SERVFAIL;
+ }
+ } else {
+ knot_response_set_rcode(resp,
+ KNOT_RCODE_NOERROR);
+ }
+ knot_response_set_aa(resp);
+ goto finalize;
+ }
+ // else set the node from which to take the answers to wild.node
+ node = wildcard_node;
+ }
+
+ // now we have the node for answering
+ if (knot_node_is_deleg_point(node) || knot_node_is_non_auth(node)) {
+ ret = ns_referral(node, zone, qname, resp);
+ goto finalize;
+ }
+
+ if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL) {
+dbg_ns_exec(
+ char *name = knot_dname_to_str(node->owner);
+ dbg_ns("Node %s has CNAME record, resolving...\n",
+ name);
+ free(name);
+);
+ const knot_dname_t *act_name = qname;
+ ns_follow_cname(&node, &act_name, resp,
+ knot_response_add_rrset_answer, 1);
+dbg_ns_exec(
+ char *name = (node != NULL) ? knot_dname_to_str(node->owner)
+ : "(nil)";
+ char *name2 = knot_dname_to_str(act_name);
+ dbg_ns("Canonical name: %s (%p), node found: %p\n",
+ name2, act_name, node);
+ dbg_ns("The node's owner: %s (%p)\n", name, (node != NULL)
+ ? node->owner : NULL);
+ if (node != NULL) {
+ free(name);
+ }
+ free(name2);
+);
+ qname = act_name;
+ cname = 1;
+
+ // otherwise search for the new name
+ if (node == NULL) {
+ goto search;
+ } else if (node->owner != act_name) {
+ // the stored node is closest encloser
+ find_ret = KNOT_ZONE_NAME_NOT_FOUND;
+ closest_encloser = node;
+ node = NULL;
+ goto have_node;
+ } // else do nothing, just continue
+ }
+
+ ret = ns_answer_from_node(node, closest_encloser, previous, zone, qname,
+ qtype, resp);
+ if (ret == NS_ERR_SERVFAIL) {
+ // in this case we should drop the response and send an error
+ // for now, just send the error code with a non-complete answer
+// knot_response_set_rcode(resp, KNOT_RCODE_SERVFAIL);
+// goto finalize;
+ return ret;
+ } else if (ret != KNOT_EOK) {
+ /*! \todo Handle RCODE return values!!! */
+ goto finalize;
+ }
+ knot_response_set_aa(resp);
+ knot_response_set_rcode(resp, KNOT_RCODE_NOERROR);
+
+ // this is the only case when the servers answers from
+ // particular node, i.e. the only case when it may return SOA
+ // or NS records in Answer section
+ if (DNSSEC_ENABLED
+ && knot_query_dnssec_requested(knot_packet_query(resp))
+ && node == knot_zone_contents_apex(zone)
+ && (qtype == KNOT_RRTYPE_SOA || qtype == KNOT_RRTYPE_NS)) {
+ ns_add_dnskey(node, resp);
+ }
+
+finalize:
+ if (ret == KNOT_EOK && auth_soa) {
+ ns_put_authority_soa(zone, resp);
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Answers the query from the given zone database.
+ *
+ * First it searches for a zone to answer from. If there is none, it sets
+ * RCODE REFUSED to the response and ends. Otherwise it tries to answer the
+ * query using the found zone (see ns_answer_from_zone()).
+ *
+ * \param db Zone database to use for answering.
+ * \param resp Response that holds the parsed query.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_answer(knot_zonedb_t *db, knot_packet_t *resp)
+{
+ const knot_dname_t *qname = knot_packet_qname(resp);
+ assert(qname != NULL);
+
+ uint16_t qtype = knot_packet_qtype(resp);
+dbg_ns_exec(
+ char *name_str = knot_dname_to_str(qname);
+ dbg_ns("Trying to find zone for QNAME %s\n", name_str);
+ free(name_str);
+);
+ // find zone in which to search for the name
+ const knot_zone_t *zone =
+ ns_get_zone_for_qname(db, qname, qtype);
+ const knot_zone_contents_t *contents = knot_zone_contents(zone);
+
+ // if no zone found, return REFUSED
+ if (zone == NULL) {
+ dbg_ns("No zone found.\n");
+ knot_response_set_rcode(resp, KNOT_RCODE_REFUSED);
+ //knot_dname_free(&qname);
+ return KNOT_EOK;
+ } else if (contents == NULL) {
+ dbg_ns("Zone expired or not bootstrapped. Reply SERVFAIL.\n");
+ knot_response_set_rcode(resp, KNOT_RCODE_SERVFAIL);
+ return KNOT_EOK;
+ }
+
+dbg_ns_exec(
+ char *name_str2 = knot_dname_to_str(zone->contents->apex->owner);
+ dbg_ns("Found zone for QNAME %s\n", name_str2);
+ free(name_str2);
+);
+
+ // take the zone contents and use only them for answering
+
+ return ns_answer_from_zone(contents, qname, qtype, resp);
+
+ //knot_dname_free(&qname);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Converts the response to wire format.
+ *
+ * \param resp Response to convert.
+ * \param wire Place for the wire format of the response.
+ * \param wire_size In: space available for the wire format in bytes.
+ * Out: actual size of the wire format in bytes.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_response_to_wire(knot_packet_t *resp, uint8_t *wire,
+ size_t *wire_size)
+{
+ uint8_t *rwire = NULL;
+ size_t rsize = 0;
+ int ret = 0;
+
+ if ((ret = knot_packet_to_wire(resp, &rwire, &rsize))
+ != KNOT_EOK) {
+ dbg_ns("Error converting response packet "
+ "to wire format (error %d).\n", ret);
+ return NS_ERR_SERVFAIL;
+ }
+
+ if (rsize > *wire_size) {
+ dbg_ns("Reponse size (%zu) larger than allowed wire size "
+ "(%zu).\n", rsize, *wire_size);
+ return NS_ERR_SERVFAIL;
+ }
+
+ if (rwire != wire) {
+ dbg_ns("Wire format reallocated, copying to place for "
+ "wire.\n");
+ memcpy(wire, rwire, rsize);
+ } else {
+ dbg_ns("Using the same space or wire format.\n");
+ }
+
+ *wire_size = rsize;
+ //free(rwire);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates a wire format of an error response from partially created
+ * response.
+ *
+ * \param resp Response to use.
+ * \param wire Place for the wire format of the response.
+ * \param wire_size In: space available for the wire format in bytes.
+ * Out: actual size of the wire format in bytes.
+ *
+ * \retval KNOT_EOK
+ * \retval NS_ERR_SERVFAIL
+ */
+static int ns_error_response_to_wire(knot_packet_t *resp, uint8_t *wire,
+ size_t *wire_size)
+{
+ /* Do not call the packet conversion function
+ * wire format is assembled, but COUNTs in header are not set.
+ * This is ideal, we just truncate the packet after the question.
+ */
+ dbg_ns("Creating error response.\n");
+
+ size_t rsize = knot_packet_question_size(knot_packet_query(resp));
+ dbg_ns("Error response (~ query) size: %zu\n", rsize);
+
+ // take 'qsize' from the current wireformat of the response
+ // it is already assembled - Header and Question section are copied
+ const uint8_t *rwire = knot_packet_wireformat(resp);
+ if (rsize > *wire_size) {
+ dbg_ns("Reponse size (%zu) larger than allowed wire size"
+ " (%zu).\n", rsize, *wire_size);
+ return NS_ERR_SERVFAIL;
+ }
+
+ assert(rwire != wire);
+
+ /*! \todo Why is this copied?? Why we cannot use resp->wireformat?? */
+ memcpy(wire, rwire, rsize);
+
+ *wire_size = rsize;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct ns_axfr_params {
+ knot_ns_xfr_t *xfr;
+ int ret;
+} ns_axfr_params_t;
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_tsig_required(int packet_nr)
+{
+ dbg_ns_detail("ns_tsig_required(%d): %d\n", packet_nr,
+ (packet_nr % KNOT_NS_TSIG_FREQ == 0));
+ return (packet_nr % KNOT_NS_TSIG_FREQ == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig)
+{
+ assert(xfr != NULL);
+ assert(xfr->query != NULL);
+ assert(xfr->response != NULL);
+ assert(xfr->wire != NULL);
+ assert(xfr->send != NULL);
+
+ // Transform the packet into wire format
+ dbg_ns("Converting response to wire format..\n");
+ size_t real_size = xfr->wire_size;
+ if (ns_response_to_wire(xfr->response, xfr->wire, &real_size) != 0) {
+ return NS_ERR_SERVFAIL;
+// // send back SERVFAIL (as this is our problem)
+// ns_error_response(nameserver,
+// knot_wire_get_id(query_wire),
+// KNOT_RCODE_SERVFAIL, response_wire,
+// rsize);
+ }
+
+ int res = 0;
+
+ size_t digest_real_size = xfr->digest_max_size;
+
+ dbg_ns_detail("xfr->tsig_key=%p\n", xfr->tsig_key);
+ /*! \note [TSIG] Generate TSIG if required (during XFR/IN). */
+ if (xfr->tsig_key && add_tsig) {
+ if (xfr->packet_nr == 0) {
+ /* Add key, digest and digest length. */
+ dbg_ns_detail("Calling tsig_sign(): %p, %zu, %zu, "
+ "%p, %zu, %p, %zu, %p\n",
+ xfr->wire, real_size, xfr->wire_size,
+ xfr->digest, xfr->digest_size, xfr->digest,
+ digest_real_size, xfr->tsig_key);
+ res = knot_tsig_sign(xfr->wire, &real_size,
+ xfr->wire_size, xfr->digest,
+ xfr->digest_size, xfr->digest,
+ &digest_real_size,
+ xfr->tsig_key);
+ } else {
+ /* Add key, digest and digest length. */
+ dbg_ns_detail("Calling tsig_sign_next()\n");
+ res = knot_tsig_sign_next(xfr->wire, &real_size,
+ xfr->wire_size,
+ xfr->digest,
+ xfr->digest_size,
+ xfr->digest,
+ &digest_real_size,
+ xfr->tsig_key);
+ }
+
+ dbg_ns_detail("Sign function returned: %s\n",
+ knot_strerror(res));
+ dbg_ns_detail("Real size of digest: %zu\n", digest_real_size);
+
+ if (res != KNOT_EOK) {
+ return res;
+ }
+
+ assert(digest_real_size > 0);
+ // save the new previous digest size
+ xfr->digest_size = digest_real_size;
+ }
+
+ // Send the response
+ dbg_ns("Sending response (size %zu)..\n", real_size);
+ //dbg_ns_hex((const char *)xfr->wire, real_size);
+ res = xfr->send(xfr->session, &xfr->addr, xfr->wire, real_size);
+ if (res < 0) {
+ dbg_ns("Send returned %d\n", res);
+ return res;
+ } else if (res != real_size) {
+ dbg_ns("AXFR did not send right amount of bytes."
+ " Transfer size: %zu, sent: %d\n",
+ real_size, res);
+ }
+
+ // Clean the response structure
+ dbg_ns("Clearing response structure..\n");
+ knot_response_clear(xfr->response, 0);
+
+ // increment the packet number
+ ++xfr->packet_nr;
+ if (xfr->tsig_key && add_tsig) {
+ knot_packet_set_tsig_size(xfr->response, xfr->tsig_size);
+ } else {
+ knot_packet_set_tsig_size(xfr->response, 0);
+ }
+
+ dbg_ns("Response structure after clearing:\n");
+ knot_packet_dump(xfr->response);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void ns_axfr_from_node(knot_node_t *node, void *data)
+{
+ assert(node != NULL);
+ assert(data != NULL);
+
+ ns_axfr_params_t *params = (ns_axfr_params_t *)data;
+
+ if (params->ret != KNOT_EOK) {
+ // just skip (will be called on next node with the same params
+ dbg_ns("Params contain error: %s, skipping node...\n",
+ knot_strerror(params->ret));
+ return;
+ }
+
+ dbg_ns("Params OK, answering AXFR from node %p.\n", node);
+dbg_ns_exec(
+ char *name = knot_dname_to_str(knot_node_owner(node));
+ dbg_ns("Node ownerr: %s\n", name);
+ free(name);
+);
+
+ if (knot_node_rrset_count(node) == 0) {
+ return;
+ }
+
+ const knot_rrset_t **rrsets = knot_node_rrsets(node);
+ if (rrsets == NULL) {
+ params->ret = KNOT_ENOMEM;
+ return;
+ }
+
+ int i = 0;
+ int ret = 0;
+ const knot_rrset_t *rrset = NULL;
+ while (i < knot_node_rrset_count(node)) {
+ assert(rrsets[i] != NULL);
+ rrset = rrsets[i];
+rrset:
+ dbg_ns(" Type: %s\n",
+ knot_rrtype_to_string(knot_rrset_type(rrset)));
+
+ // do not add SOA
+ if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) {
+ ++i;
+ continue;
+ }
+
+ ret = knot_response_add_rrset_answer(params->xfr->response,
+ rrset, 0, 0, 1);
+
+ if (ret == KNOT_ESPACE) {
+ // TODO: send the packet and clean the structure
+ dbg_ns("Packet full, sending..\n");
+ ret = ns_xfr_send_and_clear(params->xfr,
+ knot_ns_tsig_required(params->xfr->packet_nr));
+ if (ret != KNOT_EOK) {
+ // some wierd problem, we should end
+ params->ret = KNOT_ERROR;
+ break;
+ }
+ // otherwise try once more with the same RRSet
+ goto rrset;
+ } else if (ret != KNOT_EOK) {
+ // some wierd problem, we should end
+ params->ret = KNOT_ERROR;
+ break;
+ }
+
+ // we can send the RRSets in any order, so add the RRSIGs now
+ rrset = knot_rrset_rrsigs(rrset);
+rrsigs:
+ if (rrset == NULL) {
+ ++i;
+ continue;
+ }
+
+ ret = knot_response_add_rrset_answer(params->xfr->response,
+ rrset, 0, 0, 1);
+
+ if (ret == KNOT_ESPACE) {
+ // TODO: send the packet and clean the structure
+ dbg_ns("Packet full, sending..\n");
+ ret = ns_xfr_send_and_clear(params->xfr,
+ knot_ns_tsig_required(params->xfr->packet_nr));
+ if (ret != KNOT_EOK) {
+ // some wierd problem, we should end
+ params->ret = KNOT_ERROR;
+ break;
+ }
+ // otherwise try once more with the same RRSet
+ goto rrsigs;
+ } else if (ret != KNOT_EOK) {
+ // some wierd problem, we should end
+ params->ret = KNOT_ERROR;
+ break;
+ }
+
+ // this way only whole RRSets are always sent
+ // we guess it will not create too much overhead
+
+ ++i;
+ }
+ if (rrsets != NULL) {
+ free(rrsets);
+ }
+
+ /*! \todo maybe distinguish some error codes. */
+ //params->ret = (ret == 0) ? KNOT_EOK : KNOT_ERROR;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ns_axfr_from_zone(knot_zone_contents_t *zone, knot_ns_xfr_t *xfr)
+{
+ assert(xfr != NULL);
+ assert(xfr->query != NULL);
+ assert(xfr->response != NULL);
+ assert(xfr->wire != NULL);
+ assert(xfr->send != NULL);
+
+ ns_axfr_params_t params;
+ memset(&params, 0, sizeof(ns_axfr_params_t));
+ params.xfr = xfr;
+ params.ret = KNOT_EOK;
+
+ xfr->packet_nr = 0;
+
+ /*
+ * First SOA
+ */
+
+ // retrieve SOA - must be send as first and last RR
+ const knot_rrset_t *soa_rrset = knot_node_rrset(
+ knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
+ if (soa_rrset == NULL) {
+ // some really serious error
+ return KNOT_ERROR;
+ }
+
+ int ret;
+
+ // add SOA RR to the response
+ ret = knot_response_add_rrset_answer(xfr->response, soa_rrset, 0, 0, 1);
+ if (ret != KNOT_EOK) {
+ // something is really wrong
+ return KNOT_ERROR;
+ }
+
+ // add the SOA's RRSIG
+ const knot_rrset_t *rrset = knot_rrset_rrsigs(soa_rrset);
+ if (rrset != NULL
+ && (ret = knot_response_add_rrset_answer(xfr->response, rrset,
+ 0, 0, 1)) != KNOT_EOK) {
+ // something is really wrong, these should definitely fit in
+ return KNOT_ERROR;
+ }
+
+ knot_zone_contents_tree_apply_inorder(zone, ns_axfr_from_node,
+ &params);
+
+ if (params.ret != KNOT_EOK) {
+ return KNOT_ERROR; // maybe do something with the code
+ }
+
+ knot_zone_contents_nsec3_apply_inorder(zone, ns_axfr_from_node,
+ &params);
+
+ if (params.ret != KNOT_EOK) {
+ return KNOT_ERROR; // maybe do something with the code
+ }
+
+ /*
+ * Last SOA
+ */
+
+ // try to add the SOA to the response again (last RR)
+ ret = knot_response_add_rrset_answer(xfr->response, soa_rrset, 0, 0, 1);
+ if (ret == KNOT_ESPACE) {
+
+ // if there is not enough space, send the response and
+ // add the SOA record to a new packet
+ dbg_ns("Packet full, sending..\n");
+ ret = ns_xfr_send_and_clear(xfr,
+ knot_ns_tsig_required(xfr->packet_nr));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = knot_response_add_rrset_answer(xfr->response,
+ soa_rrset, 0, 0, 1);
+ if (ret != KNOT_EOK) {
+ return KNOT_ERROR;
+ }
+
+ } else if (ret != KNOT_EOK) {
+ // something is really wrong
+ return KNOT_ERROR;
+ }
+
+ dbg_ns("Sending packet...\n");
+ return ns_xfr_send_and_clear(xfr, 1);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ns_ixfr_put_rrset(knot_ns_xfr_t *xfr, const knot_rrset_t *rrset)
+{
+ int res = knot_response_add_rrset_answer(xfr->response, rrset,
+ 0, 0, 0);
+ if (res == KNOT_ESPACE) {
+ knot_response_set_rcode(xfr->response, KNOT_RCODE_NOERROR);
+ /*! \todo Probably rename the function. */
+ ns_xfr_send_and_clear(xfr, knot_ns_tsig_required(xfr->packet_nr));
+
+ res = knot_response_add_rrset_answer(xfr->response,
+ rrset, 0, 0, 0);
+ }
+
+ if (res != KNOT_EOK) {
+ dbg_ns("Error putting origin SOA to IXFR reply: %s\n",
+ knot_strerror(res));
+ /*! \todo Probably send back AXFR instead. */
+ knot_response_set_rcode(xfr->response,
+ KNOT_RCODE_SERVFAIL);
+ /*! \todo Probably rename the function. */
+ ns_xfr_send_and_clear(xfr, 1);
+ //socket_close(xfr->session); /*! \todo Remove for UDP.*/
+ return KNOT_ERROR;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ns_ixfr_put_changeset(knot_ns_xfr_t *xfr, const knot_changeset_t *chgset)
+{
+ // 1) put origin SOA
+ int res = ns_ixfr_put_rrset(xfr, chgset->soa_from);
+ if (res != KNOT_EOK) {
+ return res;
+ }
+
+ // 2) put remove RRSets
+ for (int i = 0; i < chgset->remove_count; ++i) {
+ res = ns_ixfr_put_rrset(xfr, chgset->remove[i]);
+ if (res != KNOT_EOK) {
+ return res;
+ }
+ }
+
+ // 1) put target SOA
+ res = ns_ixfr_put_rrset(xfr, chgset->soa_to);
+ if (res != KNOT_EOK) {
+ return res;
+ }
+
+ // 2) put remove RRSets
+ for (int i = 0; i < chgset->add_count; ++i) {
+ res = ns_ixfr_put_rrset(xfr, chgset->add[i]);
+ if (res != KNOT_EOK) {
+ return res;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr)
+{
+ assert(xfr != NULL);
+ assert(xfr->zone != NULL);
+ assert(xfr->query != NULL);
+ assert(xfr->response != NULL);
+ assert(knot_packet_authority_rrset_count(xfr->query) > 0);
+ assert(xfr->data != NULL);
+
+ /*! \todo REMOVE start */
+// const knot_rrset_t *zone_soa =
+// knot_node_rrset(knot_zone_contents_apex(
+// knot_zone_contents(xfr->zone)),
+// KNOT_RRTYPE_SOA);
+// // retrieve origin (xfr) serial and target (zone) serial
+// uint32_t zone_serial = knot_rdata_soa_serial(
+// knot_rrset_rdata(zone_soa));
+// uint32_t xfr_serial = knot_rdata_soa_serial(knot_rrset_rdata(
+// knot_packet_authority_rrset(xfr->query, 0)));
+
+// // 3) load changesets from journal
+// knot_changesets_t *chgsets = (knot_changesets_t *)
+// calloc(1, sizeof(knot_changesets_t));
+// int res = xfr_load_changesets(xfr->zone, chgsets, xfr_serial,
+// zone_serial);
+// if (res != KNOT_EOK) {
+// dbg_ns("IXFR query cannot be answered: %s.\n",
+// knot_strerror(res));
+// /*! \todo Probably send back AXFR instead. */
+// knot_response_set_rcode(xfr->response, KNOT_RCODE_SERVFAIL);
+// /*! \todo Probably rename the function. */
+// ns_axfr_send_and_clear(xfr);
+// //socket_close(xfr->session); /*! \todo Remove for UDP. */
+// return 1;
+// }
+
+ /*! \todo REMOVE end */
+
+ knot_changesets_t *chgsets = (knot_changesets_t *)xfr->data;
+ knot_zone_contents_t* contents = knot_zone_get_contents(xfr->zone);
+ assert(contents);
+ const knot_rrset_t *zone_soa =
+ knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA);
+
+ // 4) put the zone SOA as the first Answer RR
+ int res = knot_response_add_rrset_answer(xfr->response, zone_soa, 0,
+ 0, 0);
+ if (res != KNOT_EOK) {
+ dbg_ns("IXFR query cannot be answered: %s.\n",
+ knot_strerror(res));
+ knot_response_set_rcode(xfr->response,
+ KNOT_RCODE_SERVFAIL);
+ /*! \todo Probably rename the function. */
+ ns_xfr_send_and_clear(xfr, 1);
+// socket_close(xfr->session); /*! \todo Remove for UDP.*/
+ return 1;
+ }
+
+ // 5) put the changesets into the response while they fit in
+ for (int i = 0; i < chgsets->count; ++i) {
+ res = ns_ixfr_put_changeset(xfr, &chgsets->sets[i]);
+ if (res != KNOT_EOK) {
+ // answer is sent, socket is closed
+ return KNOT_EOK;
+ }
+ }
+
+ if (chgsets->count > 0) {
+ res = ns_ixfr_put_rrset(xfr, zone_soa);
+ }
+
+ if (res == KNOT_EOK) {
+ /*! \todo Probably rename the function. */
+ ns_xfr_send_and_clear(xfr, 1);
+ //socket_close(xfr->session); /*! \todo Remove for UDP.*/
+ return 1;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int ns_ixfr(knot_ns_xfr_t *xfr)
+{
+ assert(xfr != NULL);
+ assert(xfr->query != NULL);
+ assert(xfr->response != NULL);
+ assert(knot_packet_qtype(xfr->response) == KNOT_RRTYPE_IXFR);
+
+ // check if there is the required authority record
+ if ((knot_packet_authority_rrset_count(xfr->query) <= 0)) {
+ // malformed packet
+ dbg_ns("IXFR query does not contain authority record.\n");
+ knot_response_set_rcode(xfr->response, KNOT_RCODE_FORMERR);
+ /*! \todo Probably rename the function. */
+ ns_xfr_send_and_clear(xfr, 1);
+ //socket_close(xfr->session);
+ return 1;
+ }
+
+ const knot_rrset_t *soa = knot_packet_authority_rrset(xfr->query, 0);
+ const knot_dname_t *qname = knot_packet_qname(xfr->response);
+
+ // check if XFR QNAME and SOA correspond
+ if (knot_packet_qtype(xfr->query) != KNOT_RRTYPE_IXFR
+ || knot_rrset_type(soa) != KNOT_RRTYPE_SOA
+ || knot_dname_compare(qname, knot_rrset_owner(soa)) != 0) {
+ // malformed packet
+ dbg_ns("IXFR query is malformed.\n");
+ knot_response_set_rcode(xfr->response, KNOT_RCODE_FORMERR);
+ /*! \todo Probably rename the function. */
+ ns_xfr_send_and_clear(xfr, 1);
+ //socket_close(xfr->session); /*! \todo Remove for UDP. */
+ return 1;
+ }
+
+ return ns_ixfr_from_zone(xfr);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ns_prepare_response(knot_nameserver_t *nameserver,
+ knot_packet_t *query, knot_packet_t **resp,
+ size_t max_size)
+{
+ assert(max_size >= 500);
+
+ // initialize response packet structure
+ *resp = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ if (*resp == NULL) {
+ dbg_ns("Failed to create packet structure.\n");
+ return KNOT_ENOMEM;
+ }
+
+ int ret = knot_packet_set_max_size(*resp, max_size);
+ //(*resp)->wireformat = response_wire;;
+ //(*resp)->max_size = max_size;
+
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to init response structure.\n");
+ knot_packet_free(resp);
+ return ret;
+ }
+
+ ret = knot_response_init_from_query(*resp, query);
+
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to init response structure.\n");
+ knot_packet_free(resp);
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int32_t ns_serial_difference(uint32_t s1, uint32_t s2)
+{
+ return (((int64_t)s1 - s2) % ((int64_t)1 << 32));
+}
+
+/*----------------------------------------------------------------------------*/
+/* Public functions */
+/*----------------------------------------------------------------------------*/
+
+knot_nameserver_t *knot_ns_create()
+{
+ knot_nameserver_t *ns = malloc(sizeof(knot_nameserver_t));
+ if (ns == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ ns->data = 0;
+
+ // Create zone database structure
+ dbg_ns("Creating Zone Database structure...\n");
+ ns->zone_db = knot_zonedb_new();
+ if (ns->zone_db == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ns);
+ return NULL;
+ }
+
+ // prepare empty response with SERVFAIL error
+ knot_packet_t *err = knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ if (err == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ns);
+ return NULL;
+ }
+
+ dbg_ns("Created default empty response...\n");
+
+ int rc = knot_packet_set_max_size(err, KNOT_WIRE_HEADER_SIZE);
+ if (rc != KNOT_EOK) {
+ dbg_ns("Error creating default error response: %s.\n",
+ knot_strerror(rc));
+ free(ns);
+ knot_packet_free(&err);
+ return NULL;
+ }
+
+ rc = knot_response_init(err);
+ if (rc != KNOT_EOK) {
+ dbg_ns("Error initializing default error response:"
+ " %s.\n", knot_strerror(rc));
+ free(ns);
+ knot_packet_free(&err);
+ return NULL;
+ }
+
+ knot_response_set_rcode(err, KNOT_RCODE_SERVFAIL);
+ ns->err_resp_size = 0;
+
+ dbg_ns("Converting default empty response to wire format...\n");
+
+ uint8_t *error_wire = NULL;
+
+ if (knot_packet_to_wire(err, &error_wire, &ns->err_resp_size) != 0) {
+ dbg_ns("Error while converting "
+ "default error response to "
+ "wire format \n");
+ knot_packet_free(&err);
+ free(ns);
+ return NULL;
+ }
+
+ ns->err_response = (uint8_t *)malloc(ns->err_resp_size);
+ if (ns->err_response == NULL) {
+ dbg_ns("Error while converting default "
+ "error response to wire format \n");
+ knot_packet_free(&err);
+ free(ns);
+ return NULL;
+ }
+
+ memcpy(ns->err_response, error_wire, ns->err_resp_size);
+
+ dbg_ns("Done..\n");
+
+ knot_packet_free(&err);
+
+ if (EDNS_ENABLED) {
+ ns->opt_rr = knot_edns_new();
+ if (ns->opt_rr == NULL) {
+ dbg_ns("Error while preparing OPT RR of the"
+ " server.\n");
+ knot_packet_free(&err);
+ free(ns);
+ return NULL;
+ }
+ knot_edns_set_version(ns->opt_rr, EDNS_VERSION);
+ knot_edns_set_payload(ns->opt_rr, MAX_UDP_PAYLOAD_EDNS);
+ } else {
+ ns->opt_rr = NULL;
+ }
+
+ knot_packet_free(&err);
+
+ return ns;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize,
+ knot_packet_t *packet, knot_packet_type_t *type)
+{
+ if (packet == NULL || query_wire == NULL || type == NULL) {
+ dbg_ns("Missing parameter to query parsing.\n");
+ return KNOT_EBADARG;
+ }
+
+ dbg_ns("ns_parse_packet() called with query size %zu.\n", qsize);
+ //dbg_ns_hex((char *)query_wire, qsize);
+
+ if (qsize < 2) {
+ return KNOT_EMALF;
+ }
+
+ // 1) create empty response
+ dbg_ns("Parsing packet...\n");
+ //parsed = knot_response_new_empty(NULL);
+
+ int ret = 0;
+
+ if ((ret = knot_packet_parse_from_wire(packet, query_wire,
+ qsize, 1)) != 0) {
+ dbg_ns("Error while parsing packet, "
+ "libknot error '%s'.\n", knot_strerror(ret));
+// knot_response_free(&parsed);
+ return KNOT_RCODE_FORMERR;
+ }
+
+ dbg_ns("Parsed packet header and Question:\n");
+ knot_packet_dump(packet);
+
+ // 3) determine the query type
+ switch (knot_packet_opcode(packet)) {
+ case KNOT_OPCODE_QUERY:
+ switch (knot_packet_qtype(packet)) {
+ case KNOT_RRTYPE_AXFR:
+ *type = (knot_packet_is_query(packet))
+ ? KNOT_QUERY_AXFR : KNOT_RESPONSE_AXFR;
+ break;
+ case KNOT_RRTYPE_IXFR:
+ *type = (knot_packet_is_query(packet))
+ ? KNOT_QUERY_IXFR : KNOT_RESPONSE_IXFR;
+ break;
+ default:
+ *type = (knot_packet_is_query(packet))
+ ? KNOT_QUERY_NORMAL : KNOT_RESPONSE_NORMAL;
+ }
+
+ break;
+ case KNOT_OPCODE_NOTIFY:
+ *type = (knot_packet_is_query(packet))
+ ? KNOT_QUERY_NOTIFY : KNOT_RESPONSE_NOTIFY;
+ break;
+ case KNOT_OPCODE_UPDATE:
+ if(knot_packet_is_query(packet)) {
+ *type = KNOT_QUERY_UPDATE;
+ } else {
+ return KNOT_RCODE_FORMERR;
+ }
+ break;
+ default:
+ return KNOT_RCODE_NOTIMPL;
+ }
+
+// knot_packet_free(&packet);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_ns_error_response(const knot_nameserver_t *nameserver, uint16_t query_id,
+ uint8_t rcode, uint8_t *response_wire, size_t *rsize)
+{
+ //dbg_ns("Error response: \n");
+ //dbg_ns_hex((const char *)nameserver->err_response,
+ // nameserver->err_resp_size);
+
+ memcpy(response_wire, nameserver->err_response,
+ nameserver->err_resp_size);
+ // copy ID of the query
+ knot_wire_set_id(response_wire, query_id);
+ // set the RCODE
+ knot_wire_set_rcode(response_wire, rcode);
+ *rsize = nameserver->err_resp_size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_ns_error_response_full(knot_nameserver_t *nameserver,
+ knot_packet_t *response, uint8_t rcode,
+ uint8_t *response_wire, size_t *rsize)
+{
+ knot_response_set_rcode(response, rcode);
+
+ if (ns_error_response_to_wire(response, response_wire, rsize) != 0) {
+ knot_ns_error_response(nameserver, knot_packet_id(
+ knot_packet_query(response)),
+ KNOT_RCODE_SERVFAIL, response_wire,
+ rsize);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_answer_normal(knot_nameserver_t *nameserver, knot_packet_t *query,
+ uint8_t *response_wire, size_t *rsize)
+{
+ dbg_ns("ns_answer_normal()\n");
+
+ // first, parse the rest of the packet
+ assert(knot_packet_is_query(query));
+ dbg_ns("Query - parsed: %zu, total wire size: %zu\n",
+ knot_packet_parsed(query), knot_packet_size(query));
+ int ret;
+
+ ret = knot_packet_parse_rest(query);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to parse rest of the query: "
+ "%s.\n", knot_strerror(ret));
+ knot_ns_error_response(nameserver, knot_packet_id(query),
+ (ret == KNOT_EMALF)
+ ? KNOT_RCODE_FORMERR
+ : KNOT_RCODE_SERVFAIL, response_wire,
+ rsize);
+ return KNOT_EOK;
+ }
+
+ /*
+ * Semantic checks - if ANCOUNT > 0 or NSCOUNT > 0, return FORMERR.
+ *
+ * If any xxCOUNT is less or more than actual RR count
+ * the previously called knot_packet_parse_rest() will recognize this.
+ *
+ * Check the QDCOUNT and in case of anything but 1 send back
+ * FORMERR
+ */
+ if (knot_packet_ancount(query) > 0
+ || knot_packet_nscount(query) > 0
+ || knot_packet_qdcount(query) != 1) {
+ dbg_ns("ANCOUNT or NSCOUNT not 0 in query, reply FORMERR.\n");
+ knot_ns_error_response(nameserver, knot_packet_id(query),
+ KNOT_RCODE_FORMERR, response_wire,
+ rsize);
+ return KNOT_EOK;
+ }
+
+ size_t resp_max_size = 0;
+
+ assert(*rsize >= MAX_UDP_PAYLOAD);
+
+ knot_packet_dump(query);
+
+ if (knot_query_edns_supported(query)) {
+ if (knot_edns_get_payload(&query->opt_rr) <
+ knot_edns_get_payload(nameserver->opt_rr)) {
+ resp_max_size = knot_edns_get_payload(&query->opt_rr);
+ } else {
+ resp_max_size = knot_edns_get_payload(
+ nameserver->opt_rr);
+ }
+ }
+
+ if (resp_max_size < MAX_UDP_PAYLOAD) {
+ resp_max_size = MAX_UDP_PAYLOAD;
+ }
+
+ knot_packet_t *response;
+ ret = knot_ns_prepare_response(nameserver, query, &response,
+ resp_max_size);
+ if (ret != KNOT_EOK) {
+ knot_ns_error_response(nameserver, knot_packet_id(query),
+ KNOT_RCODE_SERVFAIL, response_wire,
+ rsize);
+ return KNOT_EOK;
+ }
+
+ dbg_ns("Query - parsed: %zu, total wire size: %zu\n",
+ query->parsed, query->size);
+ dbg_ns("Opt RR: version: %d, payload: %d\n",
+ query->opt_rr.version, query->opt_rr.payload);
+
+ // get the answer for the query
+ rcu_read_lock();
+ knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db);
+
+ dbg_ns("EDNS supported in query: %d\n",
+ knot_query_edns_supported(query));
+
+ // set the OPT RR to the response
+ if (knot_query_edns_supported(query)) {
+ /*! \todo API. */
+// if (knot_edns_get_payload(&query->opt_rr) > MAX_UDP_PAYLOAD) {
+// ret = knot_packet_set_max_size(response,
+// knot_edns_get_payload(&query->opt_rr));
+// } else {
+// ret = knot_packet_set_max_size(response,
+// MAX_UDP_PAYLOAD);
+// }
+
+// if (ret != KNOT_EOK) {
+// dbg_ns("Failed to set max size.\n");
+// knot_ns_error_response_full(nameserver, response,
+// KNOT_RCODE_SERVFAIL,
+// response_wire, rsize);
+// return KNOT_EOK;
+// }
+
+ ret = knot_response_add_opt(response, nameserver->opt_rr, 1);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to set OPT RR to the response"
+ ": %s\n",knot_strerror(ret));
+ } else {
+ // copy the DO bit from the query
+ if (knot_query_dnssec_requested(query)) {
+ /*! \todo API for this. */
+ knot_edns_set_do(&response->opt_rr);
+ }
+ }
+ }/* else {
+ dbg_ns("Setting max size to %u.\n", MAX_UDP_PAYLOAD);
+ ret = knot_packet_set_max_size(response, MAX_UDP_PAYLOAD);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to set max size to %u\n",
+ MAX_UDP_PAYLOAD);
+ knot_ns_error_response_full(nameserver, response,
+ KNOT_RCODE_SERVFAIL,
+ response_wire, rsize);
+ return KNOT_EOK;
+ }
+ }*/
+
+ dbg_ns("Response max size: %zu\n", response->max_size);
+
+ ret = ns_answer(zonedb, response);
+ if (ret != 0) {
+ // now only one type of error (SERVFAIL), later maybe more
+ knot_ns_error_response_full(nameserver, response,
+ KNOT_RCODE_SERVFAIL,
+ response_wire, rsize);
+ } else {
+ dbg_ns("Created response packet.\n");
+ //knot_response_dump(resp);
+ knot_packet_dump(response);
+
+ // 4) Transform the packet into wire format
+ if (ns_response_to_wire(response, response_wire, rsize) != 0) {
+ // send back SERVFAIL (as this is our problem)
+ knot_ns_error_response_full(nameserver, response,
+ KNOT_RCODE_SERVFAIL,
+ response_wire, rsize);
+ }
+ }
+
+ rcu_read_unlock();
+ knot_packet_free(&response);
+
+ dbg_ns("Returning response with wire size %zu\n", *rsize);
+ //dbg_ns_hex((char *)response_wire, *rsize);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
+{
+ dbg_ns("knot_ns_init_xfr()\n");
+
+ if (nameserver == NULL || xfr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // no need to parse rest of the packet
+ /*! \todo Parse rest of packet because of EDNS. */
+ int ret = knot_packet_parse_rest(xfr->query);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to parse rest of the query: %s\n",
+ knot_strerror(ret));
+ knot_ns_error_response(nameserver, xfr->query->header.id,
+ (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR
+ : KNOT_RCODE_SERVFAIL,
+ xfr->wire, &xfr->wire_size);
+ ret = xfr->send(xfr->session, &xfr->addr, xfr->wire,
+ xfr->wire_size);
+ return ret;
+ }
+
+ dbg_packet("Parsed XFR query:\n");
+ knot_packet_dump(xfr->query);
+
+ // initialize response packet structure
+ knot_packet_t *response = knot_packet_new(
+ KNOT_PACKET_PREALLOC_RESPONSE);
+ if (response == NULL) {
+ dbg_ns("Failed to create packet structure.\n");
+ /*! \todo xfr->wire is not NULL, will fail on assert! */
+ knot_ns_error_response(nameserver, xfr->query->header.id,
+ KNOT_RCODE_SERVFAIL, xfr->wire,
+ &xfr->wire_size);
+ ret = xfr->send(xfr->session, &xfr->addr, xfr->wire,
+ xfr->wire_size);
+ knot_packet_free(&response);
+ return ret;
+ }
+
+ //int ret = knot_packet_set_max_size(response, xfr->wire_size);
+ response->wireformat = xfr->wire;
+ response->max_size = xfr->wire_size;
+
+// if (ret != KNOT_EOK) {
+// dbg_ns("Failed to init response structure.\n");
+// /*! \todo xfr->wire is not NULL, will fail on assert! */
+// knot_ns_error_response(nameserver, xfr->query->header.id,
+// KNOT_RCODE_SERVFAIL, xfr->wire,
+// &xfr->wire_size);
+// int res = xfr->send(xfr->session, &xfr->addr, xfr->wire,
+// xfr->wire_size);
+// knot_packet_free(&response);
+// return res;
+// }
+
+ ret = knot_response_init_from_query(response, xfr->query);
+
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to init response structure.\n");
+ /*! \todo xfr->wire is not NULL, will fail on assert! */
+ knot_ns_error_response(nameserver, xfr->query->header.id,
+ KNOT_RCODE_SERVFAIL, xfr->wire,
+ &xfr->wire_size);
+ int res = xfr->send(xfr->session, &xfr->addr, xfr->wire,
+ xfr->wire_size);
+ knot_packet_free(&response);
+ return res;
+ }
+
+ xfr->response = response;
+
+ knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db);
+
+ const knot_dname_t *qname = knot_packet_qname(xfr->response);
+
+ assert(knot_packet_qtype(xfr->response) == KNOT_RRTYPE_AXFR ||
+ knot_packet_qtype(xfr->response) == KNOT_RRTYPE_IXFR);
+
+dbg_ns_exec(
+ char *name_str = knot_dname_to_str(qname);
+ dbg_ns("Trying to find zone with name %s\n", name_str);
+ free(name_str);
+);
+ // find zone in which to search for the name
+ knot_zone_t *zone = knot_zonedb_find_zone(zonedb, qname);
+
+ // if no zone found, return NotAuth
+ if (zone == NULL) {
+ dbg_ns("No zone found.\n");
+ knot_response_set_rcode(xfr->response, KNOT_RCODE_NOTAUTH);
+ ns_xfr_send_and_clear(xfr, 1);
+ return KNOT_ENOZONE;
+ }
+
+dbg_ns_exec(
+ char *name2_str = knot_dname_to_str(qname);
+ dbg_ns("Found zone for name %s\n", name2_str);
+ free(name2_str);
+);
+ xfr->zone = zone;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int ns_serial_compare(uint32_t s1, uint32_t s2)
+{
+ int32_t diff = ns_serial_difference(s1, s2);
+ return (s1 == s2) /* s1 equal to s2 */
+ ? 0
+ :((diff >= 1 && diff < ((uint32_t)1 << 31))
+ ? 1 /* s1 larger than s2 */
+ : -1); /* s1 less than s2 */
+}
+
+/*----------------------------------------------------------------------------*/
+
+int ns_ixfr_load_serials(const knot_ns_xfr_t *xfr, uint32_t *serial_from,
+ uint32_t *serial_to)
+{
+ if (xfr == NULL || xfr->zone == NULL || serial_from == NULL
+ || serial_to == NULL) {
+ dbg_ns_detail("Wrong parameters: xfr=%p,"
+ " xfr->zone = %p\n", xfr, xfr->zone);
+ return KNOT_EBADARG;
+ }
+
+ const knot_zone_t *zone = xfr->zone;
+ const knot_zone_contents_t *contents = knot_zone_contents(zone);
+ if (!contents) {
+ dbg_ns_detail("Missing contents\n");
+ return KNOT_EBADARG;
+ }
+
+ if (knot_zone_contents_apex(contents) == NULL) {
+ dbg_ns_detail("No apex.\n");
+ return KNOT_EBADARG;
+ }
+
+ const knot_rrset_t *zone_soa =
+ knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA);
+ if (zone_soa == NULL) {
+ dbg_ns_verb("No SOA.\n");
+ return KNOT_EBADARG;
+ }
+
+ if (knot_packet_nscount(xfr->query) < 1) {
+ dbg_ns_verb("No Authority record.\n");
+ return KNOT_EMALF;
+ }
+
+ if (knot_packet_authority_rrset(xfr->query, 0) == NULL) {
+ dbg_ns_verb("Authority record missing.\n");
+ return KNOT_ERROR;
+ }
+
+ // retrieve origin (xfr) serial and target (zone) serial
+ *serial_to = knot_rdata_soa_serial(knot_rrset_rdata(zone_soa));
+ *serial_from = knot_rdata_soa_serial(knot_rrset_rdata(
+ knot_packet_authority_rrset(xfr->query, 0)));
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_xfr_send_error(const knot_nameserver_t *nameserver,
+ knot_ns_xfr_t *xfr, knot_rcode_t rcode)
+{
+ /*! \todo Handle TSIG errors differently. */
+ knot_response_set_rcode(xfr->response, rcode);
+
+ /*! \todo Probably rename the function. */
+ int ret = 0;
+ if ((ret = ns_xfr_send_and_clear(xfr, 1)) != KNOT_EOK) {
+ size_t size = 0;
+ knot_ns_error_response(nameserver, xfr->query->header.id,
+ KNOT_RCODE_SERVFAIL, xfr->wire, &size);
+ ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size);
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
+{
+ if (xfr == NULL || nameserver == NULL || xfr->zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ rcu_read_lock();
+
+ // take the contents and answer from them
+ int ret = 0;
+ knot_zone_contents_t *contents = knot_zone_get_contents(xfr->zone);
+ if (!contents) {
+ dbg_ns("AXFR failed on stub zone\n");
+ /*! \todo replace with knot_ns_xfr_send_error() */
+ knot_ns_error_response(nameserver, xfr->query->header.id,
+ KNOT_RCODE_SERVFAIL, xfr->wire,
+ &xfr->wire_size);
+ ret = xfr->send(xfr->session, &xfr->addr, xfr->wire,
+ xfr->wire_size);
+ rcu_read_unlock();
+ knot_packet_free(&xfr->response);
+ return KNOT_EOK;
+ }
+
+ /*!
+ * \todo [TSIG] The TSIG data should already be stored in 'xfr'.
+ * Now just count the expected size of the TSIG RR and save it
+ * to the response structure.
+ */
+
+ /*! \todo [TSIG] Get the TSIG size from some API function. */
+ if (xfr->tsig_size > 0) {
+ dbg_ns_detail("Setting TSIG size in packet: %zu\n",
+ xfr->tsig_size);
+ knot_packet_set_tsig_size(xfr->response, xfr->tsig_size);
+ }
+
+ ret = ns_axfr_from_zone(contents, xfr);
+
+ /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL
+ * and when it does not. E.g. if there was problem in sending
+ * packet, it will probably fail when sending the SERVFAIL also.
+ */
+ if (ret < 0) {
+ dbg_ns("AXFR failed, sending SERVFAIL.\n");
+ // now only one type of error (SERVFAIL), later maybe more
+ /*! \todo xfr->wire is not NULL, will fail on assert! */
+ /*! \todo replace with knot_ns_xfr_send_error() */
+ knot_ns_error_response(nameserver, xfr->query->header.id,
+ KNOT_RCODE_SERVFAIL, xfr->wire,
+ &xfr->wire_size);
+ ret = xfr->send(xfr->session, &xfr->addr, xfr->wire,
+ xfr->wire_size);
+ } else if (ret > 0) {
+ ret = KNOT_ERROR;
+ }
+
+ rcu_read_unlock();
+
+ knot_packet_free(&xfr->response);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
+{
+ if (nameserver == NULL || xfr == NULL || xfr->zone == NULL
+ || xfr->response == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ //uint8_t *wire = NULL;
+ //size_t size = xfr->wire_size;
+
+ // parse rest of the packet (we need the Authority record)
+ int ret = knot_packet_parse_rest(xfr->query);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to parse rest of the packet. Reply FORMERR.\n");
+// knot_ns_error_response_full(nameserver, xfr->response,
+// KNOT_RCODE_FORMERR, xfr->wire,
+// &size);
+ knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_FORMERR);
+
+ //ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size);
+ knot_packet_free(&xfr->response);
+ return ret;
+ }
+
+ // check if the zone has contents
+ if (knot_zone_contents(xfr->zone) == NULL) {
+ dbg_ns("Zone expired or not bootstrapped. Reply SERVFAIL.\n");
+ ret = knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL);
+// knot_ns_error_response_full(nameserver, xfr->response,
+// KNOT_RCODE_SERVFAIL, xfr->wire,
+// &size);
+
+// ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size);
+ knot_packet_free(&xfr->response);
+ return ret;
+ }
+
+ /*!
+ * \todo [TSIG] The TSIG data should already be stored in 'xfr'.
+ * Now just count the expected size of the TSIG RR and save it
+ * to the response structure. This should be optional, only if
+ * the request contained TSIG, i.e. if there is the data in 'xfr'.
+ */
+
+ /*! \todo [TSIG] Get the TSIG size from some API function. */
+ if (xfr->tsig_size > 0) {
+ knot_packet_set_tsig_size(xfr->response, xfr->tsig_size);
+ }
+
+ ret = ns_ixfr(xfr);
+
+ /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL
+ * and when it does not. E.g. if there was problem in sending
+ * packet, it will probably fail when sending the SERVFAIL also.
+ */
+ if (ret < 0) {
+ dbg_ns("IXFR failed, sending SERVFAIL.\n");
+ // now only one type of error (SERVFAIL), later maybe more
+
+ /*! \todo Extract this to some function. */
+// knot_response_set_rcode(xfr->response, KNOT_RCODE_SERVFAIL);
+// uint8_t *wire = NULL;
+// ret = knot_packet_to_wire(xfr->response, &wire, &size);
+// if (ret != KNOT_EOK) {
+//// knot_ns_error_response(nameserver,
+//// xfr->query->header.id,
+//// KNOT_RCODE_SERVFAIL, xfr->wire,
+//// &size);
+//// ret = xfr->send(xfr->session, &xfr->addr, xfr->wire,
+//// size);
+// knot_ns_xfr_send_error(xfr, KNOT_RCODE_SERVFAIL);
+// knot_packet_free(&xfr->response);
+// return ret;
+// } else {
+// ret = xfr->send(xfr->session, &xfr->addr, wire, size);
+// }
+ knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL);
+ } /*else if (ret > 0) {
+ ret = KNOT_ERROR;
+ }*/
+
+ knot_packet_free(&xfr->response);
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
+{
+ /*!
+ * \todo [TSIG] Here we assume that 'xfr' contains TSIG information
+ * and the digest of the query sent to the master or the previous
+ * digest.
+ */
+
+ dbg_ns("ns_process_axfrin: incoming packet, wire size: %zu\n",
+ xfr->wire_size);
+
+ int ret = xfrin_process_axfr_packet(/*xfr->wire, xfr->wire_size,*/
+ /*(xfrin_constructed_zone_t **)(&xfr->data)*/
+ xfr);
+
+ if (ret > 0) { // transfer finished
+ dbg_ns("ns_process_axfrin: AXFR finished, zone created.\n");
+ /*
+ * Adjust zone so that node count is set properly and nodes are
+ * marked authoritative / delegation point.
+ */
+ xfrin_constructed_zone_t *constr_zone =
+ (xfrin_constructed_zone_t *)xfr->data;
+ knot_zone_contents_t *zone = constr_zone->contents;
+ assert(zone != NULL);
+
+ dbg_ns("ns_process_axfrin: adjusting zone.\n");
+ knot_zone_contents_adjust(zone, 0);
+
+ /* Create and fill hash table */
+ dbg_ns("ns_process_axfrin: filling hash table.\n");
+ int rc = knot_zone_contents_create_and_fill_hash_table(zone);
+ if (rc != KNOT_EOK) {
+ return KNOT_ERROR; // TODO: change error code
+ }
+
+ // save the zone contents to the xfr->data
+ xfr->data = zone;
+
+ // free the structure used for processing XFR
+ assert(constr_zone->rrsigs == NULL);
+ free(constr_zone);
+
+ //knot_zone_contents_dump(zone, 0);
+ }
+
+ /*!
+ * \todo In case of error, shouldn't the zone be destroyed here?
+ */
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_switch_zone(knot_nameserver_t *nameserver,
+ knot_ns_xfr_t *xfr)
+{
+ if (xfr == NULL || nameserver == NULL || xfr->data == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_contents_t *zone = (knot_zone_contents_t *)xfr->data;
+
+ dbg_ns("Replacing zone by new one: %p\n", zone);
+
+ // find the zone in the zone db
+ knot_zone_t *z = knot_zonedb_find_zone(nameserver->zone_db,
+ knot_node_owner(knot_zone_contents_apex(zone)));
+ if (z == NULL) {
+ char *name = knot_dname_to_str(knot_node_owner(
+ knot_zone_contents_apex(zone)));
+ dbg_ns("Failed to replace zone %s, old zone "
+ "not found\n", name);
+ free(name);
+ } else {
+ zone->zone = z;
+ }
+
+ knot_zone_contents_t *old = rcu_xchg_pointer(&z->contents, zone);
+
+// knot_zone_t *old = knot_zonedb_replace_zone(nameserver->zone_db,
+// zone);
+ dbg_ns("Old zone: %p\n", old);
+// if (old == NULL) {
+// char *name = knot_dname_to_str(
+// knot_node_owner(knot_zone_apex(zone)));
+// dbg_ns("Failed to replace zone %s\n", name);
+// free(name);
+// }
+
+ // wait for readers to finish
+ dbg_ns("Waiting for readers to finish...\n");
+ synchronize_rcu();
+ // destroy the old zone
+ dbg_ns("Freeing old zone: %p\n", old);
+ knot_zone_contents_deep_free(&old, 0);
+
+dbg_ns_exec(
+ dbg_ns("Zone db contents: (zone count: %zu)\n",
+ nameserver->zone_db->zone_count);
+
+ const knot_zone_t **zones = knot_zonedb_zones(nameserver->zone_db);
+ for (int i = 0; i < knot_zonedb_zone_count
+ (nameserver->zone_db); i++) {
+ dbg_ns("%d. zone: %p", i, zones[i]);
+ char *name = knot_dname_to_str(zones[i]->name);
+ dbg_ns(" zone name: %s\n", name);
+ free(name);
+ }
+ free(zones);
+);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*! \todo In this function, xfr->zone is properly set. If this is so, we do not
+ * have to search for the zone after the transfer has finished.
+ */
+int knot_ns_process_ixfrin(knot_nameserver_t *nameserver,
+ knot_ns_xfr_t *xfr)
+{
+ dbg_ns("ns_process_ixfrin: incoming packet\n");
+
+ /*!
+ * \todo [TSIG] Here we assume that 'xfr' contains TSIG information
+ * and the digest of the query sent to the master or the previous
+ * digest.
+ */
+
+ int ret = xfrin_process_ixfr_packet(xfr/*xfr->wire, xfr->wire_size,
+ (knot_changesets_t **)(&xfr->data)*/);
+
+ if (ret == XFRIN_RES_FALLBACK) {
+ dbg_ns("ns_process_ixfrin: Fallback to AXFR.\n");
+ assert(xfr->data == NULL);
+// dbg_ns("xfr->zone = %p\n", xfr->zone);
+// dbg_ns("Zone name: %.*s\n",
+// xfr->zone->name->size, xfr->zone->name->name);
+// assert(xfr->zone == NULL);
+ knot_packet_free(&xfr->query);
+ return KNOT_ENOIXFR;
+ }
+
+ if (ret > 0) {
+ dbg_ns("ns_process_ixfrin: IXFR finished\n");
+
+ knot_changesets_t *chgsets = (knot_changesets_t *)xfr->data;
+ if (chgsets == NULL || chgsets->first_soa == NULL) {
+ // nothing to be done??
+ dbg_ns("No changesets created for incoming IXFR!\n");
+ return ret;
+ }
+
+ // find zone associated with the changesets
+ knot_zone_t *zone = knot_zonedb_find_zone(
+ nameserver->zone_db,
+ knot_rrset_owner(chgsets->first_soa));
+ if (zone == NULL) {
+ dbg_ns("No zone found for incoming IXFR!\n");
+ knot_free_changesets(
+ (knot_changesets_t **)(&xfr->data));
+ return KNOT_ENOZONE; /*! \todo Other error code? */
+ }
+
+ switch (ret) {
+ case XFRIN_RES_COMPLETE:
+ xfr->zone = zone;
+ break;
+ case XFRIN_RES_SOA_ONLY: {
+ // compare the SERIAL from the changeset with the zone's
+ // serial
+ const knot_node_t *apex = knot_zone_contents_apex(
+ knot_zone_contents(zone));
+ if (apex == NULL) {
+ return KNOT_ERROR;
+ }
+
+ const knot_rrset_t *zone_soa = knot_node_rrset(
+ apex, KNOT_RRTYPE_SOA);
+ if (zone_soa == NULL) {
+ return KNOT_ERROR;
+ }
+
+ if (knot_rdata_soa_serial(knot_rrset_rdata(
+ chgsets->first_soa))
+ != knot_rdata_soa_serial(knot_rrset_rdata(
+ zone_soa))) {
+ dbg_ns("Update did not fit.\n");
+ return KNOT_EAGAIN;
+ } else {
+ // free changesets
+ dbg_ns("No update needed.\n");
+ knot_free_changesets(
+ (knot_changesets_t **)(&xfr->data));
+ return KNOT_ENOXFR;
+ }
+ } break;
+ }
+ }
+
+ /*!
+ * \todo In case of error, shouldn't the zone be destroyed here?
+ */
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query,
+ uint8_t *response_wire, size_t *rsize,
+ knot_zone_t **zone, knot_changeset_t **changeset)
+{
+ // 1) Parse the rest of the packet
+ assert(knot_packet_is_query(query));
+
+ knot_packet_t *response;
+ assert(*rsize >= MAX_UDP_PAYLOAD);
+ int ret = knot_ns_prepare_response(nameserver, query, &response,
+ MAX_UDP_PAYLOAD);
+ if (ret != KNOT_EOK) {
+ knot_ns_error_response(nameserver, knot_packet_id(query),
+ KNOT_RCODE_SERVFAIL, response_wire,
+ rsize);
+ return KNOT_EOK;
+ }
+
+ assert(response != NULL);
+
+ dbg_ns("Query - parsed: %zu, total wire size: %zu\n",
+ query->parsed, query->size);
+
+ if (knot_packet_parsed(query) < knot_packet_size(query)) {
+ ret = knot_packet_parse_rest(query);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to parse rest of the query: "
+ "%s.\n", knot_strerror(ret));
+ knot_ns_error_response_full(nameserver, response,
+ (ret == KNOT_EMALF)
+ ? KNOT_RCODE_FORMERR
+ : KNOT_RCODE_SERVFAIL,
+ response_wire, rsize);
+ knot_packet_free(&response);
+ return KNOT_EOK;
+ }
+ }
+
+ dbg_ns("Query - parsed: %zu, total wire size: %zu\n",
+ knot_packet_parsed(query), knot_packet_size(query));
+
+ /*! \todo API for EDNS values. */
+ dbg_ns("Opt RR: version: %d, payload: %d\n",
+ query->opt_rr.version, query->opt_rr.payload);
+
+ // 2) Find zone for the query
+ // we do not check if there is only one entry in the Question section
+ // because the packet structure does not allow it
+ /*! \todo Check number of Question entries while parsing. */
+ if (knot_packet_qtype(query) != KNOT_RRTYPE_SOA) {
+ dbg_ns("Question is not of type SOA.\n");
+ knot_ns_error_response_full(nameserver, response,
+ KNOT_RCODE_FORMERR,
+ response_wire, rsize);
+ knot_packet_free(&response);
+ return KNOT_EOK;
+ }
+
+ *zone = knot_zonedb_find_zone(nameserver->zone_db,
+ knot_packet_qname(query));
+ if (*zone == NULL) {
+ dbg_ns("Zone not found for the update.\n");
+ knot_ns_error_response_full(nameserver, response,
+ KNOT_RCODE_NOTAUTH,
+ response_wire, rsize);
+ knot_packet_free(&response);
+ return KNOT_EOK;
+ }
+
+ uint8_t rcode = 0;
+ // 3) Check zone
+ ret = knot_ddns_check_zone(*zone, query, &rcode);
+ if (ret == KNOT_EBADZONE) {
+ // zone is slave, forward the request
+ /*! \todo Implement forwarding. */
+ return KNOT_EBADZONE;
+ } else if (ret != KNOT_EOK) {
+ dbg_ns("Failed to check zone for update: "
+ "%s.\n", knot_strerror(ret));
+ knot_ns_error_response_full(nameserver, response, rcode,
+ response_wire, rsize);
+ knot_packet_free(&response);
+ return KNOT_EOK;
+ }
+
+ // 4) Convert prerequisities
+ knot_ddns_prereq_t *prereqs = NULL;
+ ret = knot_ddns_process_prereqs(query, &prereqs, &rcode);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to check zone for update: "
+ "%s.\n", knot_strerror(ret));
+ knot_ns_error_response_full(nameserver, response, rcode,
+ response_wire, rsize);
+ knot_packet_free(&response);
+ return KNOT_EOK;
+ }
+
+ assert(prereqs != NULL);
+
+ // 5) Check prerequisities
+ /*! \todo Somehow ensure the zone will not be changed until the update
+ * is finished.
+ */
+ ret = knot_ddns_check_prereqs(knot_zone_contents(*zone), &prereqs,
+ &rcode);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to check zone for update: "
+ "%s.\n", knot_strerror(ret));
+ knot_ns_error_response_full(nameserver, response, rcode,
+ response_wire, rsize);
+ knot_ddns_prereqs_free(&prereqs);
+ knot_packet_free(&response);
+ return KNOT_EOK;
+ }
+
+ // 6) Convert update to changeset
+ ret = knot_ddns_process_update(query, changeset, &rcode);
+ if (ret != KNOT_EOK) {
+ dbg_ns("Failed to check zone for update: "
+ "%s.\n", knot_strerror(ret));
+ knot_ns_error_response_full(nameserver, response, rcode,
+ response_wire, rsize);
+ knot_ddns_prereqs_free(&prereqs);
+ knot_packet_free(&response);
+ return KNOT_EOK;
+ }
+
+ assert(changeset != NULL);
+
+ // 7) Create response
+ dbg_ns("Update converted successfuly.\n");
+
+ /*! \todo No response yet. Distinguish somehow in the caller.
+ * Maybe only this case will be EOK, other cases some error.
+ */
+
+ knot_packet_free(&response);
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_create_forward_query(const knot_packet_t *query,
+ uint8_t *query_wire, size_t *size)
+{
+ // just copy the wireformat of the query and set a new random ID to it
+ if (knot_packet_size(query) > *size) {
+ return KNOT_ESPACE;
+ }
+
+ memcpy(query_wire, knot_packet_wireformat(query),
+ knot_packet_size(query));
+ *size = knot_packet_size(query);
+
+ knot_wire_set_id(query_wire, knot_random_id());
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ns_process_forward_response(const knot_packet_t *response,
+ uint16_t original_id,
+ uint8_t *response_wire, size_t *size)
+{
+ // just copy the wireformat of the response and set the original ID
+
+ if (knot_packet_size(response) > *size) {
+ return KNOT_ESPACE;
+ }
+
+ memcpy(response_wire, knot_packet_wireformat(response),
+ knot_packet_size(response));
+ *size = knot_packet_size(response);
+
+ knot_wire_set_id(response_wire, original_id);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void *knot_ns_data(knot_nameserver_t *nameserver)
+{
+ return nameserver->data;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void *knot_ns_get_data(knot_nameserver_t *nameserver)
+{
+ return nameserver->data;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_ns_set_data(knot_nameserver_t *nameserver, void *data)
+{
+ nameserver->data = data;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_ns_destroy(knot_nameserver_t **nameserver)
+{
+ synchronize_rcu();
+
+ free((*nameserver)->err_response);
+ if ((*nameserver)->opt_rr != NULL) {
+ knot_edns_free(&(*nameserver)->opt_rr);
+ }
+
+ // destroy the zone db
+ knot_zonedb_deep_free(&(*nameserver)->zone_db);
+
+ free(*nameserver);
+ *nameserver = NULL;
+}
diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h
new file mode 100644
index 0000000..0d93df6
--- /dev/null
+++ b/src/libknot/nameserver/name-server.h
@@ -0,0 +1,358 @@
+/*!
+ * \file name-server.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * Contains the "name server" structure and interface for the main DNS
+ * functions. Currently only supports answering simple queries, without any
+ * extensions.
+ *
+ * \todo Consider saving pointer to the zdb_find_name() function in the
+ * nameserver structure. Probably not needed, these modules can be
+ * inter-connected.
+ * \todo Provide interface for other DNS functions - zone transfers, dynamic
+ * updates, etc.
+ *
+ * \addtogroup query_processing
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_NAME_SERVER_H_
+#define _KNOT_NAME_SERVER_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "zone/zonedb.h"
+#include "edns.h"
+#include "consts.h"
+#include "tsig.h"
+#include "packet/packet.h"
+#include "common/sockaddr.h"
+#include "updates/changesets.h"
+
+struct conf_t;
+struct server_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Name server structure. Holds all important data needed for the
+ * supported DNS functions.
+ *
+ * Currently only holds pointer to the zone database for answering queries.
+ */
+typedef struct knot_nameserver {
+ /*!
+ * \brief Pointer to the zone database structure used for answering
+ * queries.
+ */
+ knot_zonedb_t *zone_db;
+ uint8_t *err_response; /*!< Prepared generic error response. */
+ size_t err_resp_size; /*!< Size of the prepared error response. */
+ knot_opt_rr_t *opt_rr; /*!< OPT RR with the server's EDNS0 info. */
+
+ void *data;
+} knot_nameserver_t;
+
+/*! \brief Callback for sending one packet back through a TCP connection. */
+typedef int (*xfr_callback_t)(int session, sockaddr_t *addr,
+ uint8_t *packet, size_t size);
+
+/*!
+ * \brief Single XFR operation structure.
+ *
+ * Used for communication with XFR handler.
+ */
+typedef struct knot_ns_xfr {
+ int type;
+ int flags;
+ sockaddr_t addr;
+ knot_packet_t *query;
+ knot_packet_t *response;
+ xfr_callback_t send;
+ int session;
+
+ /*!
+ * XFR-out: Output buffer.
+ * XFR-in: Buffer for query or incoming packet.
+ */
+ uint8_t *wire;
+
+ /*!
+ * XFR-out: Size of the output buffer.
+ * XFR-in: Size of the current packet.
+ */
+ size_t wire_size;
+ void *data;
+ knot_zone_t *zone;
+ void *owner;
+
+ /*! \note [TSIG] TSIG fields */
+ /*! \brief Message(s) to sign in wireformat.
+ *
+ * This field should be allocated at the start of transfer and
+ * freed at the end. During the transfer it is only rewritten.
+ */
+ uint8_t *tsig_data;
+ size_t tsig_data_size; /*!< Size of the message(s) in bytes */
+// const knot_rrset_t *tsig; /*!< Response TSIG.
+// \todo [TSIG] Replace with separate data. */
+ size_t tsig_size; /*!< Size of the TSIG RR wireformat in bytes.*/
+ knot_key_t *tsig_key; /*!< Associated TSIG key for signing. */
+
+ uint8_t *digest; /*!< Buffer for counting digest. */
+ size_t digest_size; /*!< Size of the digest. */
+ size_t digest_max_size; /*!< Size of the buffer. */
+
+ /*! \brief Previous digest or request digest.
+ *
+ * Should be allocated before the transfer (known size).
+ */
+// uint8_t *prev_digest;
+// size_t prev_digest_size; /*!< Size of previous digest in bytes. */
+
+ /*!
+ * \brief Number of the packet currently assembled.
+ *
+ * In case of XFR-in, this is not the overall number of packet, just
+ * number counted from last TSIG check.
+ */
+ int packet_nr;
+} knot_ns_xfr_t;
+
+
+static const int KNOT_NS_TSIG_FREQ = 100;
+
+static const size_t KNOT_NS_TSIG_DATA_MAX_SIZE = 100 * 64 * 1024;
+
+/*!
+ * \brief XFR request flags.
+ */
+enum knot_ns_xfr_flag_t {
+ XFR_FLAG_TCP = 1 << 0, /*!< XFR request is on TCP. */
+ XFR_FLAG_UDP = 1 << 1 /*!< XFR request is on UDP. */
+};
+
+/*!
+ * \brief XFR request types.
+ */
+typedef enum knot_ns_xfr_type_t {
+ /* Special events. */
+ XFR_TYPE_CLOSE = -1, /*!< Close connection event. */
+
+ /* DNS events. */
+ XFR_TYPE_AIN = 0, /*!< AXFR-IN request (start transfer). */
+ XFR_TYPE_AOUT, /*!< AXFR-OUT request (incoming transfer). */
+ XFR_TYPE_IIN, /*!< IXFR-IN request (start transfer). */
+ XFR_TYPE_IOUT, /*!< IXFR-OUT request (incoming transfer). */
+ XFR_TYPE_SOA, /*!< Pending SOA request. */
+ XFR_TYPE_NOTIFY /*!< Pending NOTIFY query. */
+} knot_ns_xfr_type_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Allocates and initializes the name server structure.
+ *
+ * \return Pointer to the name server structure.
+ */
+knot_nameserver_t *knot_ns_create();
+
+/*!
+ * \brief Parses the given query into the response structure and recognizes
+ * type of the query.
+ *
+ * Some query types are distinguished by OPCODE (NOTIFY, UPDATE, etc.), some
+ * by QTYPE (AXFR, IXFR). As these information are needed on the same layer
+ * to decide what to do with the query, the knot_query_t type is used for this
+ * purpose.
+ *
+ * \param query_wire Wire format of the query.
+ * \param qsize Size of the query in octets.
+ * \param packet Packet structure to be filled with the parsed query.
+ * \param type Type of the query.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EMALF if the query is totally unusable. Such query must be
+ * ignored.
+ * \retval KNOT_RCODE_SERVFAIL if there was some internal error. Call
+ * ns_error_response() with \a rcode set to this
+ * value to get proper error response.
+ * \retval KNOT_RCODE_FORMERR if the query was malformed, but can be used to
+ * construct an error response. Call
+ * ns_error_response() with \a rcode set to this
+ * value to get proper error response.
+ * \retval KNOT_RCODE_NOTIMPL if the query has an unsupported type. Call
+ * ns_error_response() with \a rcode set to this
+ * value to get proper error response.
+ */
+int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize,
+ knot_packet_t *packet, knot_packet_type_t *type);
+
+/*!
+ * \brief Prepares wire format of an error response using generic error template
+ * stored in the nameserver structure.
+ *
+ * The error response will not contain the Question section from the query, just
+ * a header with ID copied from the query and the given RCODE.
+ *
+ * \param nameserver Nameserver structure containing the error template.
+ * \param query_id ID of the query.
+ * \param rcode RCODE to set in the response.
+ * \param response_wire Place for wire format of the response.
+ * \param rsize Size of the error response will be stored here.
+ */
+void knot_ns_error_response(const knot_nameserver_t *nameserver, uint16_t query_id,
+ uint8_t rcode, uint8_t *response_wire, size_t *rsize);
+
+/*!
+ * \brief Creates a response for the given normal query using the data of the
+ * nameserver.
+ *
+ * \param nameserver Name server structure to provide the needed data.
+ * \param resp Response structure with parsed query.
+ * \param response_wire Place for the response in wire format.
+ * \param rsize Input: maximum acceptable size of the response. Output: real
+ * size of the response.
+ *
+ * \retval KNOT_EOK if a valid response was created.
+ * \retval KNOT_EMALF if an error occured and the response is not valid.
+ */
+int knot_ns_answer_normal(knot_nameserver_t *nameserver, knot_packet_t *query,
+ uint8_t *response_wire, size_t *rsize);
+
+int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr);
+
+/*!
+ * \brief Compares two zone serials.
+ *
+ * \retval < 0 if s1 is less than s2.
+ * \retval > 0 if s1 is larger than s2.
+ * \retval == 0 if s1 is equal to s2.
+ */
+int ns_serial_compare(uint32_t s1, uint32_t s2);
+
+int ns_ixfr_load_serials(const knot_ns_xfr_t *xfr, uint32_t *serial_from,
+ uint32_t *serial_to);
+
+int knot_ns_xfr_send_error(const knot_nameserver_t *nameserver,
+ knot_ns_xfr_t *xfr, knot_rcode_t rcode);
+
+/*!
+ * \brief Processes an AXFR query.
+ *
+ * This function sequentially creates DNS packets to be sent as a response
+ * to the AXFR query and sends each packet using the given callback (\a
+ * send_packet).
+ *
+ * \param nameserver Name server structure to provide the data for answering.
+ * \param xfr Persistent transfer-specific data.
+ *
+ * \note Currently only a stub which sends one error response using the given
+ * callback.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ * \retval KNOT_ENOMEM
+ * \retval KNOT_ERROR
+ *
+ * \todo Maybe the place for the wire format should be passed in as in
+ * the ns_answer_request() function...?
+ */
+int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr);
+
+/*!
+ * \brief Processes an IXFR query.
+ *
+ * \param nameserver Name server structure to provide the data for answering.
+ * \param xfr Persistent transfer-specific data.
+ *
+ * \todo Document properly.
+ */
+int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr);
+
+/*!
+ * \brief Processes an AXFR-IN packet.
+ *
+ * \param nameserver Name server structure to provide the data for answering.
+ * \param xfr Persistent transfer-specific data.
+ *
+ * \todo Document me.
+ */
+int knot_ns_process_axfrin(knot_nameserver_t *nameserver,
+ knot_ns_xfr_t *xfr);
+
+int knot_ns_switch_zone(knot_nameserver_t *nameserver,
+ knot_ns_xfr_t *xfr);
+
+/*!
+ * \brief Processes an IXFR-IN packet.
+ *
+ * \param nameserver Name server structure to provide the data for answering.
+ * \param xfr Persistent transfer-specific data.
+ *
+ * \retval KNOT_EOK If this packet was processed successfuly and another packet
+ * is expected. (RFC1995bis, case c)
+ * \retval KNOT_ENOXFR If the transfer is not taking place because server's
+ * SERIAL is the same as this client's SERIAL. The client
+ * should close the connection and do no further processing.
+ * (RFC1995bis case a).
+ * \retval KNOT_EAGAIN If the server could not fit the transfer into the packet.
+ * This should happen only if UDP was used. In this case
+ * the client should retry the request via TCP. If UDP was
+ * not used, it should be considered that the transfer was
+ * malformed and the connection should be closed.
+ * (RFC1995bis case b).
+ * \retval >0 Transfer successully finished. Changesets are created and furter
+ * processing is needed.
+ * \retval Other If any other error occured. The connection should be closed.
+ *
+ * \todo Document me.
+ */
+int knot_ns_process_ixfrin(knot_nameserver_t *nameserver,
+ knot_ns_xfr_t *xfr);
+
+int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query,
+ uint8_t *response_wire, size_t *rsize,
+ knot_zone_t **zone, knot_changeset_t **changeset);
+
+int knot_ns_create_forward_query(const knot_packet_t *query,
+ uint8_t *query_wire, size_t *size);
+
+int knot_ns_process_forward_response(const knot_packet_t *response,
+ uint16_t original_id,
+ uint8_t *response_wire, size_t *size);
+
+void *knot_ns_data(knot_nameserver_t *nameserver);
+
+void *knot_ns_get_data(knot_nameserver_t *nameserver);
+
+void knot_ns_set_data(knot_nameserver_t *nameserver, void *data);
+
+int knot_ns_tsig_required(int packet_nr);
+
+/*!
+ * \brief Properly destroys the name server structure.
+ *
+ * \param nameserver Nameserver to destroy.
+ */
+void knot_ns_destroy(knot_nameserver_t **nameserver);
+
+
+#endif /* _KNOTNAME_SERVER_H_ */
+
+/*! @} */
diff --git a/src/libknot/nsec3.c b/src/libknot/nsec3.c
new file mode 100644
index 0000000..303d2e6
--- /dev/null
+++ b/src/libknot/nsec3.c
@@ -0,0 +1,265 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+
+#include "nsec3.h"
+#include "common.h"
+#include "util/descriptor.h"
+#include "util/utils.h"
+#include "util/tolower.h"
+#include "util/error.h"
+#include "util/debug.h"
+
+/*----------------------------------------------------------------------------*/
+
+int knot_nsec3_params_from_wire(knot_nsec3_params_t *params,
+ const knot_rrset_t *nsec3param)
+{
+ if (params == NULL || nsec3param == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ assert(knot_rrset_type(nsec3param) == KNOT_RRTYPE_NSEC3PARAM);
+ const knot_rdata_t *rdata = knot_rrset_rdata(nsec3param);
+
+ assert(rdata->count == 4);
+
+ params->algorithm = *(uint8_t *)
+ (&knot_rdata_item(rdata, 0)->raw_data[1]);
+ params->flags = *(uint8_t *)
+ (&knot_rdata_item(rdata, 1)->raw_data[1]);
+ params->iterations = knot_wire_read_u16(
+ (uint8_t *)(knot_rdata_item(rdata, 2)->raw_data + 1));
+
+ params->salt_length =
+ ((uint8_t *)knot_rdata_item(rdata, 3)->raw_data)[2];
+
+ if (params->salt_length > 0) {
+ params->salt = (uint8_t *)malloc(params->salt_length);
+ CHECK_ALLOC_LOG(params->salt, -1);
+ memcpy(params->salt,
+ (uint8_t *)knot_rdata_item(rdata, 3)->raw_data + 3,
+ params->salt_length);
+ } else {
+ params->salt = NULL;
+ }
+
+ dbg_nsec3("Parsed NSEC3PARAM:\n");
+ dbg_nsec3("Algorithm: %hu\n", params->algorithm);
+ dbg_nsec3("Flags: %hu\n", params->flags);
+ dbg_nsec3("Iterations: %hu\n", params->iterations);
+ dbg_nsec3("Salt length: %hu\n", params->salt_length);
+ dbg_nsec3("Salt: ");
+ if (params->salt != NULL) {
+ dbg_nsec3_hex((char *)params->salt,
+ params->salt_length);
+ dbg_nsec3("\n");
+ } else {
+ dbg_nsec3("none\n");
+ }
+
+ return KNOT_EOK;
+}
+
+static uint8_t *knot_nsec3_to_lowercase(const uint8_t *data, size_t size)
+{
+ uint8_t *out = (uint8_t *)malloc(size);
+ CHECK_ALLOC_LOG(out, NULL);
+
+ for (int i = 0; i < size; ++i) {
+ out[i] = knot_tolower(data[i]);
+ }
+
+ return out;
+}
+
+/*----------------------------------------------------------------------------*/
+#if KNOT_NSEC3_SHA_USE_EVP
+int knot_nsec3_sha1(const knot_nsec3_params_t *params,
+ const uint8_t *data, size_t size, uint8_t **digest,
+ size_t *digest_size)
+{
+ if (digest == NULL || digest_size == NULL || data == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ uint8_t *salt = params->salt;
+ uint8_t salt_length = params->salt_length;
+ uint16_t iterations = params->iterations;
+
+ EVP_MD_CTX mdctx;
+ EVP_MD_CTX_init(&mdctx);
+
+ *digest = (uint8_t *)malloc(EVP_MD_size(EVP_sha1()));
+ if (*digest == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ uint8_t *data_low = knot_nsec3_to_lowercase(data, size);
+ if (data_low == NULL) {
+ free(*digest);
+ return -1;
+ }
+
+ const uint8_t *in = data_low;
+ unsigned in_size = size;
+
+ int res = 0;
+
+#ifdef KNOT_NSEC3_DEBUG
+ unsigned long long total_time = 0;
+ unsigned long calls = 0;
+ long time = 0;
+#endif
+
+ for (int i = 0; i <= iterations; ++i) {
+#ifdef KNOT_NSEC3_DEBUG
+ perf_begin();
+#endif
+
+ EVP_DigestInit_ex(&mdctx, EVP_sha1(), NULL);
+
+ res = EVP_DigestUpdate(&mdctx, in, in_size);
+
+ if (salt_length > 0) {
+ res = EVP_DigestUpdate(&mdctx, salt, salt_length);
+ }
+
+ EVP_DigestFinal_ex(&mdctx, *digest, digest_size);
+ in = *digest;
+ in_size = *digest_size;
+
+#ifdef KNOT_NSEC3_DEBUG
+ perf_end(time);
+ total_time += time;
+ ++calls;
+#endif
+
+ if (res != 1) {
+ dbg_nsec3("Error calculating SHA-1 hash.\n");
+ free(data_low);
+ free(*digest);
+ return -2;
+ }
+ }
+
+ EVP_MD_CTX_cleanup(&mdctx);
+
+ dbg_nsec3("NSEC3 hashing: calls: %lu, avg time per call: %f."
+ "\n", calls, (double)(total_time) / calls);
+
+ free(data_low);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+#else
+
+int knot_nsec3_sha1(const knot_nsec3_params_t *params,
+ const uint8_t *data, size_t size, uint8_t **digest,
+ size_t *digest_size)
+{
+ if (params == NULL || digest == NULL || digest_size == NULL
+ || data == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ uint8_t *salt = params->salt;
+ uint8_t salt_length = params->salt_length;
+ uint16_t iterations = params->iterations;
+
+ dbg_nsec3("Hashing: \n");
+ dbg_nsec3(" Data: %.*s \n", size, data);
+ dbg_nsec3_hex((const char *)data, size);
+ dbg_nsec3(" (size %d)\n Iterations: %u\n", (int)size, iterations);
+ dbg_nsec3(" Salt length: %u\n", salt_length);
+ dbg_nsec3(" Salt: ");
+ if (salt_length > 0) {
+ dbg_nsec3_hex((char *)salt, salt_length);
+ dbg_nsec3("\n");
+ } else {
+ dbg_nsec3("none\n");
+ }
+
+ SHA_CTX ctx;
+
+ *digest = (uint8_t *)malloc(SHA_DIGEST_LENGTH);
+ if (*digest == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ uint8_t *data_low = knot_nsec3_to_lowercase(data, size);
+ if (data_low == NULL) {
+ free(*digest);
+ return KNOT_ENOMEM;
+ }
+
+ const uint8_t *in = data_low;
+ unsigned in_size = size;
+
+ int res = 0;
+
+ // other iterations
+ for (int i = 0; i <= iterations; ++i) {
+ SHA1_Init(&ctx);
+
+ res = SHA1_Update(&ctx, in, in_size);
+
+ if (salt_length > 0) {
+ res = SHA1_Update(&ctx, salt, salt_length);
+ }
+
+ SHA1_Final(*digest, &ctx);
+
+ in = *digest;
+ in_size = SHA_DIGEST_LENGTH;
+
+ if (res != 1) {
+ dbg_nsec3("Error calculating SHA-1 hash.\n");
+ free(data_low);
+ free(*digest);
+ return KNOT_ECRYPTO;
+ }
+ }
+
+ *digest_size = SHA_DIGEST_LENGTH;
+
+ dbg_nsec3("Hash: %.*s\n", *digest_size, *digest);
+ dbg_nsec3_hex((const char *)*digest, *digest_size);
+ dbg_nsec3("\n");
+
+ free(data_low);
+ return KNOT_EOK;
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+void knot_nsec3_params_free(knot_nsec3_params_t *params)
+{
+ if (params->salt != NULL) {
+ free(params->salt);
+ }
+}
diff --git a/src/libknot/nsec3.h b/src/libknot/nsec3.h
new file mode 100644
index 0000000..0ce6899
--- /dev/null
+++ b/src/libknot/nsec3.h
@@ -0,0 +1,92 @@
+/*!
+ * \file nsec3.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Functions for calcularing NSEC3 hashes.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_NSEC3_H_
+#define _KNOT_NSEC3_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "rrset.h"
+
+#define KNOT_NSEC3_SHA_USE_EVP 0
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Structure representing the NSEC3PARAM resource record.
+ */
+struct knot_nsec3_params {
+ uint8_t algorithm; /*!< Hash algorithm. */
+ uint8_t flags; /*!< Flags. */
+ uint16_t iterations; /*!< Additional iterations of the hash function.*/
+ uint8_t salt_length; /*!< Length of the salt field in bytes. */
+ uint8_t *salt; /*!< Salt used in hashing. */
+};
+
+typedef struct knot_nsec3_params knot_nsec3_params_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Initializes the NSEC3PARAM structure.
+ *
+ * \param params NSEC3PARAM structure to initialize.
+ * \param nsec3param The NSEC3PARAM RRset.
+ *
+ * \retval KNOT_EOK on success (always).
+ */
+int knot_nsec3_params_from_wire(knot_nsec3_params_t *params,
+ const knot_rrset_t *nsec3param);
+
+/*!
+ * \brief Hashes the given data using the SHA1 hash and the given parameters.
+ *
+ * \param[in] params NSEC3PARAM structure with the required parameters for
+ * hashing.
+ * \param[in] data Data to hash.
+ * \param[in] size Size of the data in bytes.
+ * \param[out] digest Result will be store here.
+ * \param[out] digest_size Size of the result in octets will be stored here.
+ *
+ * \retval KNOT_EOK if successful.
+ * \retval KNOT_ENOMEM
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ECRYPTO
+ */
+int knot_nsec3_sha1(const knot_nsec3_params_t *params, const uint8_t *data,
+ size_t size, uint8_t **digest, size_t *digest_size);
+
+/*!
+ * \brief Properly cleans up (but does not deallocate) the NSEC3PARAM structure.
+ *
+ * \param params NSEC3PARAMS structure to clean up.
+ */
+void knot_nsec3_params_free(knot_nsec3_params_t *params);
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* _KNOT_NSEC3_H_ */
+
+/*! @} */
diff --git a/src/libknot/packet/packet.c b/src/libknot/packet/packet.c
new file mode 100644
index 0000000..82e818f
--- /dev/null
+++ b/src/libknot/packet/packet.c
@@ -0,0 +1,1532 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "packet/packet.h"
+#include "util/error.h"
+#include "util/debug.h"
+#include "common.h"
+#include "util/descriptor.h"
+#include "util/wire.h"
+
+/*----------------------------------------------------------------------------*/
+
+#define DEFAULT_RRCOUNT_QUERY(type) DEFAULT_##type##COUNT_QUERY
+#define DEFAULT_RRCOUNT(type) DEFAULT_##type##COUNT
+
+#define DEFAULT_RRSET_COUNT(type, packet) \
+ ((packet->prealloc_type == KNOT_PACKET_PREALLOC_NONE) \
+ ? 0 \
+ : (packet->prealloc_type == KNOT_PACKET_PREALLOC_QUERY) \
+ ? DEFAULT_##type##_QUERY \
+ : DEFAULT_##type)
+
+
+
+typedef enum {
+ KNOT_PACKET_DUPL_IGNORE,
+ KNOT_PACKET_DUPL_SKIP,
+ KNOT_PACKET_DUPL_MERGE
+} knot_packet_duplicate_handling_t;
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Sets all the pointers in the packet structure to the respective
+ * parts of the pre-allocated space.
+ */
+static void knot_packet_init_pointers_response(knot_packet_t *pkt)
+{
+ dbg_packet("Packet pointer: %p\n", pkt);
+
+ char *pos = (char *)pkt + PREALLOC_PACKET;
+
+ // put QNAME directly after the structure
+ pkt->question.qname = (knot_dname_t *)pos;
+ pos += PREALLOC_QNAME_DNAME;
+
+ dbg_packet("QNAME: %p\n", pkt->question.qname);
+
+ pkt->question.qname->name = (uint8_t *)pos;
+ pos += PREALLOC_QNAME_NAME;
+ pkt->question.qname->labels = (uint8_t *)pos;
+ pos += PREALLOC_QNAME_LABELS;
+
+ pkt->owner_tmp = (uint8_t *)pos;
+ dbg_packet("Tmp owner: %p\n", pkt->owner_tmp);
+ pos += PREALLOC_RR_OWNER;
+
+ // then answer, authority and additional sections
+ if (DEFAULT_ANCOUNT == 0) {
+ pkt->answer = NULL;
+ } else {
+ pkt->answer = (const knot_rrset_t **)pos;
+ pos += DEFAULT_ANCOUNT * sizeof(const knot_rrset_t *);
+ }
+
+ if (DEFAULT_NSCOUNT == 0) {
+ pkt->authority = NULL;
+ } else {
+ pkt->authority = (const knot_rrset_t **)pos;
+ pos += DEFAULT_NSCOUNT * sizeof(const knot_rrset_t *);
+ }
+
+ if (DEFAULT_ARCOUNT == 0) {
+ pkt->additional = NULL;
+ } else {
+ pkt->additional = (const knot_rrset_t **)pos;
+ pos += DEFAULT_ARCOUNT * sizeof(const knot_rrset_t *);
+ }
+
+ dbg_packet("Answer section: %p\n", pkt->answer);
+ dbg_packet("Authority section: %p\n", pkt->authority);
+ dbg_packet("Additional section: %p\n", pkt->additional);
+
+ pkt->max_an_rrsets = DEFAULT_ANCOUNT;
+ pkt->max_ns_rrsets = DEFAULT_NSCOUNT;
+ pkt->max_ar_rrsets = DEFAULT_ARCOUNT;
+
+ // then domain names for compression and offsets
+ pkt->compression.dnames = (const knot_dname_t **)pos;
+ pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(const knot_dname_t *);
+ pkt->compression.offsets = (size_t *)pos;
+ pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t);
+
+ dbg_packet("Compression dnames: %p\n", pkt->compression.dnames);
+ dbg_packet("Compression offsets: %p\n", pkt->compression.offsets);
+
+ pkt->compression.max = DEFAULT_DOMAINS_IN_RESPONSE;
+
+ pkt->tmp_rrsets = (const knot_rrset_t **)pos;
+ pos += DEFAULT_TMP_RRSETS * sizeof(const knot_rrset_t *);
+
+ dbg_packet("Tmp rrsets: %p\n", pkt->tmp_rrsets);
+
+ pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS;
+
+ assert((char *)pos == (char *)pkt + PREALLOC_RESPONSE);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Sets all the pointers in the packet structure to the respective
+ * parts of the pre-allocated space.
+ */
+static void knot_packet_init_pointers_query(knot_packet_t *pkt)
+{
+ dbg_packet("Packet pointer: %p\n", pkt);
+
+ char *pos = (char *)pkt + PREALLOC_PACKET;
+
+ // put QNAME directly after the structure
+ pkt->question.qname = (knot_dname_t *)pos;
+ pos += PREALLOC_QNAME_DNAME;
+
+ dbg_packet("QNAME: %p (%zu after start of packet)\n",
+ pkt->question.qname,
+ (void *)pkt->question.qname - (void *)pkt);
+
+ pkt->question.qname->name = (uint8_t *)pos;
+ pos += PREALLOC_QNAME_NAME;
+ pkt->question.qname->labels = (uint8_t *)pos;
+ pos += PREALLOC_QNAME_LABELS;
+
+// pkt->owner_tmp = (uint8_t *)((char *)pkt->question.qname->labels
+// + PREALLOC_QNAME_LABELS);
+
+ // then answer, authority and additional sections
+ if (DEFAULT_ANCOUNT_QUERY == 0) {
+ pkt->answer = NULL;
+ } else {
+ pkt->answer = (const knot_rrset_t **)pos;
+ pos += DEFAULT_ANCOUNT_QUERY * sizeof(const knot_rrset_t *);
+ }
+
+ if (DEFAULT_NSCOUNT_QUERY == 0) {
+ pkt->authority = NULL;
+ } else {
+ pkt->authority = (const knot_rrset_t **)pos;
+ pos += DEFAULT_NSCOUNT_QUERY * sizeof(const knot_rrset_t *);
+ }
+
+ if (DEFAULT_ARCOUNT_QUERY == 0) {
+ pkt->additional = NULL;
+ } else {
+ pkt->additional = (const knot_rrset_t **)pos;
+ pos += DEFAULT_ARCOUNT_QUERY * sizeof(const knot_rrset_t *);
+ }
+
+ dbg_packet("Answer section: %p\n", pkt->answer);
+ dbg_packet("Authority section: %p\n", pkt->authority);
+ dbg_packet("Additional section: %p\n", pkt->additional);
+
+ pkt->max_an_rrsets = DEFAULT_ANCOUNT_QUERY;
+ pkt->max_ns_rrsets = DEFAULT_NSCOUNT_QUERY;
+ pkt->max_ar_rrsets = DEFAULT_ARCOUNT_QUERY;
+
+ pkt->tmp_rrsets = (const knot_rrset_t **)pos;
+ pos += DEFAULT_TMP_RRSETS_QUERY * sizeof(const knot_rrset_t *);
+
+ dbg_packet("Tmp rrsets: %p\n", pkt->tmp_rrsets);
+
+ pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS_QUERY;
+
+// dbg_packet("End of data: %p (%zu after start of packet)\n",
+// pkt->tmp_rrsets + DEFAULT_TMP_RRSETS_QUERY,
+// (void *)(pkt->tmp_rrsets + DEFAULT_TMP_RRSETS_QUERY)
+// - (void *)pkt);
+ dbg_packet("Allocated total: %u\n", PREALLOC_QUERY);
+
+ assert(pos == (char *)pkt + PREALLOC_QUERY);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Parses DNS header from the wire format.
+ *
+ * \note This function also adjusts the position (\a pos) and size of remaining
+ * bytes in the wire format (\a remaining) according to what was parsed
+ * (though it actually always parses the 12 bytes of the header).
+ *
+ * \param[in,out] pos Wire format to parse the header from.
+ * \param[in,out] remaining Remaining size of the wire format.
+ * \param[out] header Header structure to fill in.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EFEWDATA
+ */
+static int knot_packet_parse_header(const uint8_t *wire, size_t *pos,
+ size_t size, knot_header_t *header)
+{
+ assert(wire != NULL);
+ assert(pos != NULL);
+ assert(header != NULL);
+
+ if (size - *pos < KNOT_WIRE_HEADER_SIZE) {
+ dbg_response("Not enough data to parse header.\n");
+ return KNOT_EFEWDATA;
+ }
+
+ header->id = knot_wire_get_id(wire);
+ // copy some of the flags: OPCODE and RD
+ // do this by copying flags1 and setting QR to 1, AA to 0 and TC to 0
+ header->flags1 = knot_wire_get_flags1(wire);
+// knot_wire_flags_set_qr(&header->flags1);
+// knot_wire_flags_clear_aa(&header->flags1);
+// knot_wire_flags_clear_tc(&header->flags1);
+ // do not copy flags2 (all set by server)
+ header->qdcount = knot_wire_get_qdcount(wire);
+ header->ancount = knot_wire_get_ancount(wire);
+ header->nscount = knot_wire_get_nscount(wire);
+ header->arcount = knot_wire_get_arcount(wire);
+
+ *pos += KNOT_WIRE_HEADER_SIZE;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Parses DNS Question entry from the wire format.
+ *
+ * \note This function also adjusts the position (\a pos) and size of remaining
+ * bytes in the wire format (\a remaining) according to what was parsed.
+ *
+ * \param[in,out] pos Wire format to parse the Question from.
+ * \param[in,out] remaining Remaining size of the wire format.
+ * \param[out] question DNS Question structure to be filled.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EFEWDATA
+ * \retval KNOT_ENOMEM
+ */
+static int knot_packet_parse_question(const uint8_t *wire, size_t *pos,
+ size_t size,
+ knot_question_t *question, int alloc)
+{
+ assert(pos != NULL);
+ assert(wire != NULL);
+ assert(question != NULL);
+
+ if (size - *pos < KNOT_WIRE_QUESTION_MIN_SIZE) {
+ dbg_response("Not enough data to parse question.\n");
+ return KNOT_EFEWDATA; // malformed
+ }
+
+ dbg_response("Parsing Question starting on position %zu.\n",
+ *pos);
+
+ // domain name must end with 0, so just search for 0
+ int i = *pos;
+ while (i < size && wire[i] != 0) {
+ ++i;
+ }
+
+ if (size - i - 1 < 4) {
+ dbg_response("Not enough data to parse question.\n");
+ return KNOT_EFEWDATA; // no 0 found or not enough data left
+ }
+
+ dbg_response("Parsing dname starting on position %zu and "
+ "%zu bytes long.\n", *pos, i - *pos + 1);
+ dbg_response("Alloc: %d\n", alloc);
+ if (alloc) {
+ question->qname = knot_dname_new_from_wire(
+ wire + *pos, i - *pos + 1, NULL);
+ if (question->qname == NULL) {
+ return KNOT_ENOMEM;
+ }
+ } else {
+ int res = knot_dname_from_wire(wire + *pos, i - *pos + 1,
+ NULL, question->qname);
+ if (res != KNOT_EOK) {
+ assert(res != KNOT_EBADARG);
+ return res;
+ }
+ }
+
+ *pos = i + 1;
+ question->qtype = knot_wire_read_u16(wire + i + 1);
+ //*pos += 2;
+ question->qclass = knot_wire_read_u16(wire + i + 3);
+ //*pos += 2;
+
+ *pos += 4;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Reallocate space for RRSets.
+ *
+ * \param rrsets Space for RRSets.
+ * \param max_count Size of the space available for the RRSets.
+ * \param default_max_count Size of the space pre-allocated for the RRSets when
+ * the response structure was initialized.
+ * \param step How much the space should be increased.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+static int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets,
+ short *max_count,
+ short default_max_count, short step)
+{
+ dbg_packet("Max count: %d, default max count: %d\n",
+ *max_count, default_max_count);
+ int free_old = (*max_count) != default_max_count;
+ const knot_rrset_t **old = *rrsets;
+
+ short new_max_count = *max_count + step;
+ const knot_rrset_t **new_rrsets = (const knot_rrset_t **)malloc(
+ new_max_count * sizeof(knot_rrset_t *));
+ CHECK_ALLOC_LOG(new_rrsets, KNOT_ENOMEM);
+
+ memcpy(new_rrsets, *rrsets, (*max_count) * sizeof(knot_rrset_t *));
+
+ *rrsets = new_rrsets;
+ *max_count = new_max_count;
+
+ if (free_old) {
+ free(old);
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire,
+ size_t *pos, size_t total_size, size_t rdlength,
+ const knot_rrtype_descriptor_t *desc)
+{
+// if (desc->type == 0) {
+// dbg_packet("Unknown RR type.\n");
+// return NULL;
+// }
+
+ knot_rdata_t *rdata = knot_rdata_new();
+ if (rdata == NULL) {
+ return NULL;
+ }
+
+ int rc = knot_rdata_from_wire(rdata, wire, pos, total_size, rdlength,
+ desc);
+
+ if (rc != KNOT_EOK) {
+ dbg_packet("rdata_from_wire() returned: %s\n",
+ knot_strerror(rc));
+ knot_rdata_free(&rdata);
+ return NULL;
+ }
+
+ return rdata;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static knot_rrset_t *knot_packet_parse_rr(const uint8_t *wire, size_t *pos,
+ size_t size)
+{
+// knot_rrset_t *rrset =
+// (knot_rrset_t *)malloc(sizeof(knot_rrset_t));
+// CHECK_ALLOC_LOG(rrset, NULL);
+
+ dbg_packet("Parsing RR from position: %zu, total size: %zu\n",
+ *pos, size);
+
+ knot_dname_t *owner = knot_dname_parse_from_wire(wire, pos, size,
+ NULL);
+ dbg_packet("Created owner: %p, actual position: %zu\n", owner,
+ *pos);
+ if (owner == NULL) {
+ return NULL;
+ }
+
+dbg_packet_exec(
+ char *name = knot_dname_to_str(owner);
+ dbg_packet("Parsed name: %s\n", name);
+ free(name);
+);
+
+ //*remaining -= knot_dname_size(rrset->owner);
+
+ /*! @todo Get rid of the numerical constant. */
+ if (size - *pos < 10) {
+ dbg_packet("Malformed RR: Not enough data to parse RR"
+ " header.\n");
+ knot_dname_release(owner);
+ return NULL;
+ }
+
+ dbg_packet("Reading type from position %zu\n", *pos);
+
+ uint16_t type = knot_wire_read_u16(wire + *pos);
+ uint16_t rclass = knot_wire_read_u16(wire + *pos + 2);
+ uint32_t ttl = knot_wire_read_u32(wire + *pos + 4);
+
+ knot_rrset_t *rrset = knot_rrset_new(owner, type, rclass, ttl);
+
+ /* Owner is either referenced in rrset or rrset creation failed. */
+ knot_dname_release(owner);
+
+ /* Check rrset allocation. */
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ uint16_t rdlength = knot_wire_read_u16(wire + *pos + 8);
+
+ dbg_packet("Read RR header: type %u, class %u, ttl %u, "
+ "rdlength %u\n", rrset->type, rrset->rclass,
+ rrset->ttl, rdlength);
+
+ *pos += 10;
+
+ if (size - *pos < rdlength) {
+ dbg_packet("Malformed RR: Not enough data to parse RR"
+ " RDATA (size: %zu, position: %zu).\n",
+ size, *pos);
+ knot_rrset_deep_free(&rrset, 1, 1, 0);
+// free(rrset);
+ return NULL;
+ }
+
+ rrset->rrsigs = NULL;
+
+ if (rdlength == 0) {
+ return rrset;
+ }
+
+ // parse RDATA
+ knot_rdata_t *rdata = knot_packet_parse_rdata(wire, pos, size,
+ rdlength,
+ knot_rrtype_descriptor_by_type(rrset->type));
+ if (rdata == NULL) {
+ dbg_packet("Malformed RR: Could not parse RDATA.\n");
+ knot_rrset_deep_free(&rrset, 1, 1, 0);
+// free(rrset);
+ return NULL;
+ }
+
+ if (knot_rrset_add_rdata(rrset, rdata) != KNOT_EOK) {
+ dbg_packet("Malformed RR: Could not add RDATA to RRSet"
+ ".\n");
+ knot_rdata_free(&rdata);
+ knot_rrset_deep_free(&rrset, 1, 1, 0);
+// free(rrset);
+ return NULL;
+ }
+
+ return rrset;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_packet_add_rrset(knot_rrset_t *rrset,
+ const knot_rrset_t ***rrsets,
+ short *rrset_count,
+ short *max_rrsets,
+ short default_rrsets,
+ const knot_packet_t *packet,
+ knot_packet_duplicate_handling_t dupl)
+{
+
+ assert(rrset != NULL);
+ assert(rrsets != NULL);
+ assert(rrset_count != NULL);
+ assert(max_rrsets != NULL);
+
+dbg_packet_exec(
+ char *name = knot_dname_to_str(rrset->owner);
+ dbg_packet("packet_add_rrset(), owner: %s, type: %s\n",
+ name, knot_rrtype_to_string(rrset->type));
+ free(name);
+);
+
+ if (*rrset_count == *max_rrsets
+ && knot_packet_realloc_rrsets(rrsets, max_rrsets, default_rrsets,
+ STEP_ANCOUNT) != KNOT_EOK) {
+ return KNOT_ENOMEM;
+ }
+
+ if (dupl == KNOT_PACKET_DUPL_SKIP &&
+ knot_packet_contains(packet, rrset, KNOT_RRSET_COMPARE_PTR)) {
+ /*! \todo This should also return > 0, as it means that the
+ RRSet was not used actually. */
+ return KNOT_EOK;
+ }
+
+ if (dupl == KNOT_PACKET_DUPL_MERGE) {
+ // try to find the RRSet in this array of RRSets
+ for (int i = 0; i < *rrset_count; ++i) {
+
+dbg_packet_exec(
+ char *name = knot_dname_to_str((*rrsets)[i]->owner);
+ dbg_packet("Comparing to RRSet: owner: %s, "
+ "type: %s\n", name,
+ knot_rrtype_to_string(
+ (*rrsets)[i]->type));
+ free(name);
+);
+
+ if (knot_rrset_compare((*rrsets)[i], rrset,
+ KNOT_RRSET_COMPARE_HEADER)) {
+ //const knot_rrset_t *r = (*rrsets)
+ /*! \todo Test this!!! */
+ int rc = knot_rrset_merge(
+ (void **)((*rrsets) + i), (void **)&rrset);
+ if (rc != KNOT_EOK) {
+ return rc;
+ }
+ return 1;
+ }
+ }
+ }
+
+ (*rrsets)[*rrset_count] = rrset;
+ ++(*rrset_count);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos,
+ size_t size, uint16_t rr_count,
+ const knot_rrset_t ***rrsets,
+ short *rrset_count, short *max_rrsets,
+ short default_rrsets,
+ knot_packet_t *packet)
+{
+ assert(pos != NULL);
+ assert(wire != NULL);
+ assert(rrsets != NULL);
+ assert(rrset_count != NULL);
+ assert(max_rrsets != NULL);
+ assert(packet != NULL);
+
+ dbg_packet("Parsing RRSets starting on position: %zu\n",
+ *pos);
+
+// if (*rrsets == NULL) {
+// knot_packet_realloc_rrsets(rrsets, max_rrsets, 0, 1);
+// }
+
+ /*
+ * The RRs from one RRSet may be scattered in the current section.
+ * We must parse all RRs separately and try to add them to already
+ * parsed RRSets.
+ */
+ int err = KNOT_EOK;
+ knot_rrset_t *rrset = NULL;
+
+ for (int i = 0; i < rr_count; ++i) {
+ rrset = knot_packet_parse_rr(wire, pos, size);
+ if (rrset == NULL) {
+ dbg_packet("Failed to parse RR!\n");
+ err = KNOT_EMALF;
+ break;
+ }
+
+ err = knot_packet_add_rrset(rrset, rrsets, rrset_count,
+ max_rrsets, default_rrsets, packet,
+ KNOT_PACKET_DUPL_MERGE);
+ if (err < 0) {
+ break;
+ } else if (err > 0) { // merged
+ dbg_packet("RRSet merged, freeing.\n");
+ knot_rrset_deep_free(&rrset, 1, 0, 0); // TODO: ok??
+ continue;
+ }
+
+ err = knot_packet_add_tmp_rrset(packet, rrset);
+ if (err != KNOT_EOK) {
+ // remove the last RRSet from the list of RRSets
+ // - just decrement the count
+ --(*rrset_count);
+ knot_rrset_deep_free(&rrset, 1, 1, 1);
+ break;
+ }
+ }
+
+ return (err < 0) ? err : KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Deallocates all space which was allocated additionally to the
+ * pre-allocated space of the response structure.
+ *
+ * \param resp Response structure that holds pointers to the allocated space.
+ */
+static void knot_packet_free_allocated_space(knot_packet_t *pkt)
+{
+ dbg_packet("Freeing additional space in packet.\n");
+ if (pkt->prealloc_type == KNOT_PACKET_PREALLOC_NONE) {
+ dbg_packet("Freeing QNAME.\n");
+ knot_dname_release(pkt->question.qname);
+ }
+
+ if (pkt->max_an_rrsets > DEFAULT_RRSET_COUNT(ANCOUNT, pkt)) {
+ free(pkt->answer);
+ }
+ if (pkt->max_ns_rrsets > DEFAULT_RRSET_COUNT(NSCOUNT, pkt)) {
+ free(pkt->authority);
+ }
+ if (pkt->max_ar_rrsets > DEFAULT_RRSET_COUNT(ARCOUNT, pkt)) {
+ free(pkt->additional);
+ }
+
+ if (pkt->compression.max > DEFAULT_DOMAINS_IN_RESPONSE) {
+ free(pkt->compression.dnames);
+ free(pkt->compression.offsets);
+ }
+
+ if (pkt->tmp_rrsets_max > DEFAULT_RRSET_COUNT(TMP_RRSETS, pkt)) {
+ free(pkt->tmp_rrsets);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_packet_parse_rr_sections(knot_packet_t *packet,
+ size_t *pos)
+{
+ assert(packet != NULL);
+ assert(packet->wireformat != NULL);
+ assert(packet->size > 0);
+ assert(pos != NULL);
+ assert(*pos > 0);
+
+ int err;
+
+ dbg_packet("Parsing Answer RRs...\n");
+ if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
+ packet->size, packet->header.ancount, &packet->answer,
+ &packet->an_rrsets, &packet->max_an_rrsets,
+ DEFAULT_RRSET_COUNT(ANCOUNT, packet), packet)) != KNOT_EOK) {
+ return err;
+ }
+
+ dbg_packet("Parsing Authority RRs...\n");
+ if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
+ packet->size, packet->header.nscount, &packet->authority,
+ &packet->ns_rrsets, &packet->max_ns_rrsets,
+ DEFAULT_RRSET_COUNT(NSCOUNT, packet), packet)) != KNOT_EOK) {
+ return err;
+ }
+
+ dbg_packet("Parsing Additional RRs...\n");
+ if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
+ packet->size, packet->header.arcount, &packet->additional,
+ &packet->ar_rrsets, &packet->max_ar_rrsets,
+ DEFAULT_RRSET_COUNT(ARCOUNT, packet), packet)) != KNOT_EOK) {
+ return err;
+ }
+
+ dbg_packet("Trying to find OPT RR in the packet.\n");
+
+ for (int i = 0; i < packet->ar_rrsets; ++i) {
+ assert(packet->additional[i] != NULL);
+ if (knot_rrset_type(packet->additional[i])
+ == KNOT_RRTYPE_OPT) {
+ dbg_packet("Found OPT RR, filling.\n");
+ err = knot_edns_new_from_rr(&packet->opt_rr,
+ packet->additional[i]);
+ if (err != KNOT_EOK) {
+ return err;
+ }
+ break;
+ }
+ }
+
+ packet->parsed = *pos;
+
+ if (*pos < packet->size) {
+ // some trailing garbage; ignore, but log
+ dbg_response("Packet: %zu bytes of trailing garbage "
+ "in packet.\n", packet->size - (*pos));
+ return KNOT_EMALF;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc)
+{
+ knot_packet_t *pkt;
+ void (*init_pointers)(knot_packet_t *pkt) = NULL;
+ size_t size = 0;
+
+ switch (prealloc) {
+ case KNOT_PACKET_PREALLOC_NONE:
+ size = sizeof(knot_packet_t);
+ break;
+ case KNOT_PACKET_PREALLOC_QUERY:
+ size = PREALLOC_QUERY;
+ init_pointers = knot_packet_init_pointers_query;
+ break;
+ case KNOT_PACKET_PREALLOC_RESPONSE:
+ size = PREALLOC_RESPONSE;
+ init_pointers = knot_packet_init_pointers_response;
+ break;
+ }
+
+ pkt = (knot_packet_t *)malloc(size);
+ CHECK_ALLOC_LOG(pkt, NULL);
+ memset(pkt, 0, size);
+ if (init_pointers != NULL) {
+ init_pointers(pkt);
+ }
+
+ pkt->prealloc_type = prealloc;
+
+ // set EDNS version to not supported
+ pkt->opt_rr.version = EDNS_NOT_SUPPORTED;
+
+ return pkt;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_parse_from_wire(knot_packet_t *packet,
+ const uint8_t *wireformat, size_t size,
+ int question_only)
+{
+ if (packet == NULL || wireformat == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ int err;
+
+ // save the wireformat in the packet
+ // TODO: can we just save the pointer, or we have to copy the data??
+ assert(packet->wireformat == NULL);
+ packet->wireformat = (uint8_t*)wireformat;
+ packet->size = size;
+ packet->free_wireformat = 0;
+
+ //uint8_t *pos = wireformat;
+ size_t pos = 0;
+ //size_t remaining = size;
+
+ dbg_packet("Parsing wire format of packet (size %zu).\nHeader\n",
+ size);
+ if ((err = knot_packet_parse_header(wireformat, &pos, size,
+ &packet->header)) != KNOT_EOK) {
+ return err;
+ }
+
+ packet->parsed = pos;
+
+ dbg_packet("Question (prealloc type: %d)...\n", packet->prealloc_type);
+
+ if (packet->header.qdcount > 1) {
+ dbg_packet("QDCOUNT larger than 1, FORMERR.\n");
+ return KNOT_EMALF;
+ }
+
+ knot_packet_dump(packet);
+
+ if (packet->header.qdcount == 1) {
+ if ((err = knot_packet_parse_question(wireformat, &pos, size,
+ &packet->question, packet->prealloc_type
+ == KNOT_PACKET_PREALLOC_NONE)
+ ) != KNOT_EOK) {
+ return err;
+ }
+ packet->parsed = pos;
+ }
+
+ knot_packet_dump(packet);
+
+ if (question_only) {
+ return KNOT_EOK;
+ }
+
+ /*! \todo Replace by call to parse_rest()? */
+ err = knot_packet_parse_rr_sections(packet, &pos);
+
+#ifdef KNOT_PACKET_DEBUG
+ knot_packet_dump(packet);
+#endif /* KNOT_RESPONSE_DEBUG */
+
+ return err;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_parse_rest(knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+// if (packet->parsed >= packet->size) {
+// return KNOT_EOK;
+// }
+
+ if (packet->parsed == packet->size) {
+ return KNOT_EOK;
+ }
+
+ size_t pos = packet->parsed;
+
+ return knot_packet_parse_rr_sections(packet, &pos);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_parse_next_rr_answer(knot_packet_t *packet,
+ knot_rrset_t **rr)
+{
+ if (packet == NULL || rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ *rr = NULL;
+
+ if (packet->parsed >= packet->size) {
+ assert(packet->an_rrsets <= packet->header.ancount);
+ if (packet->an_rrsets != packet->header.ancount) {
+ dbg_packet("Parsed less RRs than expected.\n");
+ return KNOT_EMALF;
+ } else {
+ dbg_packet("Whole packet parsed\n");
+ return KNOT_EOK;
+ }
+ }
+
+ if (packet->an_rrsets == packet->header.ancount) {
+ assert(packet->parsed < packet->size);
+ //dbg_packet("Trailing garbage, ignoring...\n");
+ // there may be other data in the packet
+ // (authority or additional).
+ return KNOT_EOK;
+ }
+
+ size_t pos = packet->parsed;
+
+ dbg_packet("Parsing next Answer RR (pos: %zu)...\n", pos);
+ *rr = knot_packet_parse_rr(packet->wireformat, &pos, packet->size);
+ if (*rr == NULL) {
+ dbg_packet("Failed to parse RR!\n");
+ return KNOT_EMALF;
+ }
+
+ dbg_packet("Parsed. Pos: %zu.\n", pos);
+
+ packet->parsed = pos;
+ // increment the number of answer RRSets, though there are no saved
+ // in the packet; it is OK, because packet->answer is NULL
+ ++packet->an_rrsets;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_parse_next_rr_additional(knot_packet_t *packet,
+ knot_rrset_t **rr)
+{
+ /*! \todo Implement. */
+ if (packet == NULL || rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ *rr = NULL;
+
+ if (packet->parsed >= packet->size) {
+ assert(packet->ar_rrsets <= packet->header.arcount);
+ if (packet->ar_rrsets != packet->header.arcount) {
+ dbg_packet("Parsed less RRs than expected.\n");
+ return KNOT_EMALF;
+ } else {
+ dbg_packet("Whole packet parsed\n");
+ return KNOT_EOK;
+ }
+ }
+
+ if (packet->ar_rrsets == packet->header.arcount) {
+ assert(packet->parsed < packet->size);
+ dbg_packet("Trailing garbage, ignoring...\n");
+ /*! \todo Do not ignore. */
+ return KNOT_EOK;
+ }
+
+ size_t pos = packet->parsed;
+
+ dbg_packet("Parsing next Additional RR (pos: %zu)...\n", pos);
+ *rr = knot_packet_parse_rr(packet->wireformat, &pos, packet->size);
+ if (*rr == NULL) {
+ dbg_packet("Failed to parse RR!\n");
+ return KNOT_EMALF;
+ }
+
+ dbg_packet("Parsed. Pos: %zu.\n", pos);
+
+ packet->parsed = pos;
+ // increment the number of answer RRSets, though there are no saved
+ // in the packet; it is OK, because packet->answer is NULL
+ ++packet->ar_rrsets;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+size_t knot_packet_size(const knot_packet_t *packet)
+{
+ return packet->size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+size_t knot_packet_question_size(const knot_packet_t *packet)
+{
+ return (KNOT_WIRE_HEADER_SIZE + 4
+ + knot_dname_size(packet->question.qname));
+}
+
+/*----------------------------------------------------------------------------*/
+
+size_t knot_packet_parsed(const knot_packet_t *packet)
+{
+ return packet->parsed;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_set_max_size(knot_packet_t *packet, int max_size)
+{
+ if (packet == NULL || max_size <= 0) {
+ return KNOT_EBADARG;
+ }
+
+ if (packet->max_size < max_size) {
+ // reallocate space for the wire format (and copy anything
+ // that might have been there before
+ uint8_t *wire_new = (uint8_t *)malloc(max_size);
+ if (wire_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ uint8_t *wire_old = packet->wireformat;
+
+ memcpy(wire_new, packet->wireformat, packet->max_size);
+ packet->wireformat = wire_new;
+
+ if (packet->max_size > 0 && packet->free_wireformat) {
+ free(wire_old);
+ }
+
+ packet->free_wireformat = 1;
+ }
+
+ // set max size
+ packet->max_size = max_size;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint16_t knot_packet_id(const knot_packet_t *packet)
+{
+ assert(packet != NULL);
+ return packet->header.id;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_packet_set_id(knot_packet_t *packet, uint16_t id)
+{
+ if (packet == NULL) {
+ return;
+ }
+
+ packet->header.id = id;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_packet_set_random_id(knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return;
+ }
+
+ packet->header.id = knot_random_id();
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint8_t knot_packet_opcode(const knot_packet_t *packet)
+{
+ assert(packet != NULL);
+ return knot_wire_flags_get_opcode(packet->header.flags1);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_packet_qname(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return NULL;
+ }
+
+ return packet->question.qname;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint16_t knot_packet_qtype(const knot_packet_t *packet)
+{
+ assert(packet != NULL);
+ return packet->question.qtype;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_packet_set_qtype(knot_packet_t *packet, knot_rr_type_t qtype)
+{
+ assert(packet != NULL);
+ packet->question.qtype = qtype;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint16_t knot_packet_qclass(const knot_packet_t *packet)
+{
+ assert(packet != NULL);
+ return packet->question.qclass;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_is_query(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return (knot_wire_flags_get_qr(packet->header.flags1) == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_packet_t *knot_packet_query(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return NULL;
+ }
+
+ return packet->query;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_rcode(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return knot_wire_flags_get_rcode(packet->header.flags2);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_tc(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return knot_wire_flags_get_tc(packet->header.flags1);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_qdcount(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return packet->header.qdcount;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_ancount(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return packet->header.ancount;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_nscount(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return packet->header.nscount;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_arcount(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return packet->header.arcount;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_packet_set_tsig_size(knot_packet_t *packet, size_t tsig_size)
+{
+ packet->tsig_size = tsig_size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+short knot_packet_answer_rrset_count(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return packet->an_rrsets;
+}
+
+/*----------------------------------------------------------------------------*/
+
+short knot_packet_authority_rrset_count(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return packet->ns_rrsets;
+}
+
+/*----------------------------------------------------------------------------*/
+
+short knot_packet_additional_rrset_count(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return packet->ar_rrsets;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rrset_t *knot_packet_answer_rrset(
+ const knot_packet_t *packet, short pos)
+{
+ if (packet == NULL || pos > packet->an_rrsets) {
+ return NULL;
+ }
+
+ return packet->answer[pos];
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rrset_t *knot_packet_authority_rrset(
+ knot_packet_t *packet, short pos)
+{
+ if (packet == NULL || pos > packet->ns_rrsets) {
+ return NULL;
+ }
+
+ return packet->authority[pos];
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rrset_t *knot_packet_additional_rrset(
+ knot_packet_t *packet, short pos)
+{
+ if (packet == NULL || pos > packet->ar_rrsets) {
+ return NULL;
+ }
+
+ return packet->additional[pos];
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_contains(const knot_packet_t *packet,
+ const knot_rrset_t *rrset,
+ knot_rrset_compare_type_t cmp)
+{
+ if (packet == NULL || rrset == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ for (int i = 0; i < packet->header.ancount; ++i) {
+ if (knot_rrset_compare(packet->answer[i], rrset, cmp)) {
+ return 1;
+ }
+ }
+
+ for (int i = 0; i < packet->header.nscount; ++i) {
+ if (knot_rrset_compare(packet->authority[i], rrset, cmp)) {
+ return 1;
+ }
+ }
+
+ for (int i = 0; i < packet->header.arcount; ++i) {
+ if (knot_rrset_compare(packet->additional[i], rrset, cmp)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_add_tmp_rrset(knot_packet_t *packet,
+ knot_rrset_t *tmp_rrset)
+{
+ if (packet == NULL || tmp_rrset == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ if (packet->tmp_rrsets_count == packet->tmp_rrsets_max
+ && knot_packet_realloc_rrsets(&packet->tmp_rrsets,
+ &packet->tmp_rrsets_max,
+ DEFAULT_RRSET_COUNT(TMP_RRSETS, packet),
+ STEP_TMP_RRSETS) != KNOT_EOK) {
+ return KNOT_ENOMEM;
+ }
+
+ packet->tmp_rrsets[packet->tmp_rrsets_count++] = tmp_rrset;
+ dbg_packet("Current tmp RRSets count: %d, max count: %d\n",
+ packet->tmp_rrsets_count, packet->tmp_rrsets_max);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Frees all temporary RRSets stored in the response structure.
+ *
+ * \param resp Response structure to free the temporary RRSets from.
+ */
+void knot_packet_free_tmp_rrsets(knot_packet_t *pkt)
+{
+ if (pkt == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < pkt->tmp_rrsets_count; ++i) {
+dbg_packet_exec(
+ char *name = knot_dname_to_str(
+ (((knot_rrset_t **)(pkt->tmp_rrsets))[i])->owner);
+ dbg_packet("Freeing tmp RRSet on ptr: %p (ptr to ptr:"
+ " %p, type: %s, owner: %s)\n",
+ (((knot_rrset_t **)(pkt->tmp_rrsets))[i]),
+ &(((knot_rrset_t **)(pkt->tmp_rrsets))[i]),
+ knot_rrtype_to_string(
+ (((knot_rrset_t **)(pkt->tmp_rrsets))[i])->type),
+ name);
+ free(name);
+);
+ // TODO: this is quite ugly, but better than copying whole
+ // function (for reallocating rrset array)
+ knot_rrset_deep_free(
+ &(((knot_rrset_t **)(pkt->tmp_rrsets))[i]), 1, 1, 1);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_packet_header_to_wire(const knot_header_t *header,
+ uint8_t **pos, size_t *size)
+{
+ if (header == NULL || pos == NULL || *pos == NULL || size == NULL) {
+ return;
+ }
+
+ knot_wire_set_id(*pos, header->id);
+ knot_wire_set_flags1(*pos, header->flags1);
+ knot_wire_set_flags2(*pos, header->flags2);
+ knot_wire_set_qdcount(*pos, header->qdcount);
+ knot_wire_set_ancount(*pos, header->ancount);
+ knot_wire_set_nscount(*pos, header->nscount);
+ knot_wire_set_arcount(*pos, header->arcount);
+
+ *pos += KNOT_WIRE_HEADER_SIZE;
+ *size += KNOT_WIRE_HEADER_SIZE;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_question_to_wire(knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ if (packet->size > KNOT_WIRE_HEADER_SIZE) {
+ return KNOT_ERROR;
+ }
+
+ // TODO: get rid of the numeric constants
+ size_t qsize = 4 + knot_dname_size(packet->question.qname);
+ if (qsize > packet->max_size - KNOT_WIRE_HEADER_SIZE) {
+ return KNOT_ESPACE;
+ }
+
+ // create the wireformat of Question
+ uint8_t *pos = packet->wireformat + KNOT_WIRE_HEADER_SIZE;
+ memcpy(pos, knot_dname_name(packet->question.qname),
+ knot_dname_size(packet->question.qname));
+
+ pos += knot_dname_size(packet->question.qname);
+ knot_wire_write_u16(pos, packet->question.qtype);
+ pos += 2;
+ knot_wire_write_u16(pos, packet->question.qclass);
+
+// int err = 0;
+ // TODO: put the qname into the compression table
+// // TODO: get rid of the numeric constants
+// if ((err = knot_response_store_dname_pos(&packet->compression,
+// packet->question.qname,0, 12, 12)) != KNOT_EOK) {
+// return err;
+// }
+
+ packet->size += knot_dname_size(packet->question.qname) + 4;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_edns_to_wire(knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ packet->size += knot_edns_to_wire(&packet->opt_rr,
+ packet->wireformat + packet->size,
+ packet->max_size - packet->size);
+
+ packet->header.arcount += 1;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_packet_to_wire(knot_packet_t *packet,
+ uint8_t **wire, size_t *wire_size)
+{
+ if (packet == NULL || wire == NULL || wire_size == NULL
+ || *wire != NULL) {
+ return KNOT_EBADARG;
+ }
+
+ assert(packet->size <= packet->max_size);
+
+ // if there are no additional RRSets, add EDNS OPT RR
+ if (packet->header.arcount == 0
+ && packet->opt_rr.version != EDNS_NOT_SUPPORTED) {
+ knot_packet_edns_to_wire(packet);
+ }
+
+ // set QDCOUNT (in response it is already set, in query it is needed)
+ knot_wire_set_qdcount(packet->wireformat, packet->header.qdcount);
+ // set ANCOUNT to the packet
+ knot_wire_set_ancount(packet->wireformat, packet->header.ancount);
+ // set NSCOUNT to the packet
+ knot_wire_set_nscount(packet->wireformat, packet->header.nscount);
+ // set ARCOUNT to the packet
+ knot_wire_set_arcount(packet->wireformat, packet->header.arcount);
+
+ //assert(response->size == size);
+ *wire = packet->wireformat;
+ *wire_size = packet->size;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const uint8_t *knot_packet_wireformat(const knot_packet_t *packet)
+{
+ return packet->wireformat;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_packet_free(knot_packet_t **packet)
+{
+ if (packet == NULL || *packet == NULL) {
+ return;
+ }
+
+ // free temporary domain names
+ dbg_packet("Freeing tmp RRSets...\n");
+ knot_packet_free_tmp_rrsets(*packet);
+
+ // check if some additional space was allocated for the packet
+ dbg_packet("Freeing additional allocated space...\n");
+ knot_packet_free_allocated_space(*packet);
+
+ // free the space for wireformat
+// assert((*packet)->wireformat != NULL);
+// free((*packet)->wireformat);
+ if ((*packet)->wireformat != NULL && (*packet)->free_wireformat) {
+ free((*packet)->wireformat);
+ }
+
+ dbg_packet("Freeing packet structure\n");
+ free(*packet);
+ *packet = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+#ifdef KNOT_PACKET_DEBUG
+static void knot_packet_dump_rrsets(const knot_rrset_t **rrsets,
+ int count)
+{
+ assert((rrsets != NULL && *rrsets != NULL) || count < 1);
+
+ for (int i = 0; i < count; ++i) {
+ knot_rrset_dump(rrsets[i], 0);
+ }
+}
+#endif
+/*----------------------------------------------------------------------------*/
+
+void knot_packet_dump(const knot_packet_t *packet)
+{
+ if (packet == NULL) {
+ return;
+ }
+
+#ifdef KNOT_PACKET_DEBUG
+ dbg_packet("DNS packet:\n-----------------------------\n");
+
+ dbg_packet("\nHeader:\n");
+ dbg_packet(" ID: %u", packet->header.id);
+ dbg_packet(" FLAGS: %s %s %s %s %s %s %s\n",
+ knot_wire_flags_get_qr(packet->header.flags1) ? "qr" : "",
+ knot_wire_flags_get_aa(packet->header.flags1) ? "aa" : "",
+ knot_wire_flags_get_tc(packet->header.flags1) ? "tc" : "",
+ knot_wire_flags_get_rd(packet->header.flags1) ? "rd" : "",
+ knot_wire_flags_get_ra(packet->header.flags2) ? "ra" : "",
+ knot_wire_flags_get_ad(packet->header.flags2) ? "ad" : "",
+ knot_wire_flags_get_cd(packet->header.flags2) ? "cd" : "");
+ dbg_packet(" QDCOUNT: %u\n", packet->header.qdcount);
+ dbg_packet(" ANCOUNT: %u\n", packet->header.ancount);
+ dbg_packet(" NSCOUNT: %u\n", packet->header.nscount);
+ dbg_packet(" ARCOUNT: %u\n", packet->header.arcount);
+
+ if (knot_packet_qdcount(packet) > 0) {
+ dbg_packet("\nQuestion:\n");
+ char *qname = knot_dname_to_str(packet->question.qname);
+ dbg_packet(" QNAME: %s\n", qname);
+ free(qname);
+ dbg_packet(" QTYPE: %u (%s)\n", packet->question.qtype,
+ knot_rrtype_to_string(packet->question.qtype));
+ dbg_packet(" QCLASS: %u (%s)\n", packet->question.qclass,
+ knot_rrclass_to_string(packet->question.qclass));
+ }
+
+ dbg_packet("\nAnswer RRSets:\n");
+ knot_packet_dump_rrsets(packet->answer, packet->an_rrsets);
+ dbg_packet("\nAuthority RRSets:\n");
+ knot_packet_dump_rrsets(packet->authority, packet->ns_rrsets);
+ dbg_packet("\nAdditional RRSets:\n");
+ knot_packet_dump_rrsets(packet->additional, packet->ar_rrsets);
+
+ /*! \todo Dumping of Answer, Authority and Additional sections. */
+
+ dbg_packet("\nEDNS:\n");
+ dbg_packet(" Version: %u\n", packet->opt_rr.version);
+ dbg_packet(" Payload: %u\n", packet->opt_rr.payload);
+ dbg_packet(" Extended RCODE: %u\n",
+ packet->opt_rr.ext_rcode);
+
+ dbg_packet("\nPacket size: %zu\n", packet->size);
+ dbg_packet("\n-----------------------------\n");
+#endif
+}
+
diff --git a/src/libknot/packet/packet.h b/src/libknot/packet/packet.h
new file mode 100644
index 0000000..1bf74a9
--- /dev/null
+++ b/src/libknot/packet/packet.h
@@ -0,0 +1,538 @@
+/*!
+ * \file packet.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Structure for holding DNS packet data and metadata.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_PACKET_H_
+#define _KNOT_PACKET_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "dname.h"
+#include "rrset.h"
+#include "edns.h"
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Structure for holding information needed for compressing domain names.
+ *
+ * It's a simple table of domain names and their offsets in wire format of the
+ * packet.
+ *
+ * \todo Consider using some better lookup structure, such as skip-list.
+ */
+struct knot_compressed_dnames {
+ const knot_dname_t **dnames; /*!< Domain names present in packet. */
+ size_t *offsets; /*!< Offsets of domain names in the packet. */
+ short count; /*!< Count of items in the previous arrays. */
+ short max; /*!< Capacity of the structure (allocated). */
+};
+
+typedef struct knot_compressed_dnames knot_compressed_dnames_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Structure representing the DNS packet header.
+ */
+struct knot_header {
+ uint16_t id; /*!< ID stored in host byte order. */
+ uint8_t flags1; /*!< First octet of header flags. */
+ uint8_t flags2; /*!< Second octet of header flags. */
+ uint16_t qdcount; /*!< Number of Question RRs, in host byte order. */
+ uint16_t ancount; /*!< Number of Answer RRs, in host byte order. */
+ uint16_t nscount; /*!< Number of Authority RRs, in host byte order. */
+ uint16_t arcount; /*!< Number of Additional RRs, in host byte order. */
+};
+
+typedef struct knot_header knot_header_t;
+
+/*!
+ * \brief Structure representing one Question entry in the DNS packet.
+ */
+struct knot_question {
+ knot_dname_t *qname; /*!< Question domain name. */
+ uint16_t qtype; /*!< Question TYPE. */
+ uint16_t qclass; /*!< Question CLASS. */
+};
+
+typedef struct knot_question knot_question_t;
+
+enum knot_packet_prealloc_type {
+ KNOT_PACKET_PREALLOC_NONE,
+ KNOT_PACKET_PREALLOC_QUERY,
+ KNOT_PACKET_PREALLOC_RESPONSE
+};
+
+typedef enum knot_packet_prealloc_type knot_packet_prealloc_type_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Structure representing a DNS packet.
+ *
+ * \note QNAME, Answer, Authority and Additonal sections are by default put to
+ * preallocated space after the structure with default sizes. If the
+ * space is not enough, more space is allocated dynamically.
+ */
+struct knot_packet {
+ /*! \brief DNS header. */
+ knot_header_t header;
+
+ /*!
+ * \brief Question section.
+ *
+ * \note Only one Question is supported!
+ */
+ knot_question_t question;
+
+ uint8_t *owner_tmp; /*!< Allocated space for RRSet owner wire format.*/
+
+ const knot_rrset_t **answer; /*!< Answer RRSets. */
+ const knot_rrset_t **authority; /*!< Authority RRSets. */
+ const knot_rrset_t **additional; /*!< Additional RRSets. */
+
+ short an_rrsets; /*!< Count of Answer RRSets in the response. */
+ short ns_rrsets; /*!< Count of Authority RRSets in the response. */
+ short ar_rrsets; /*!< Count of Additional RRSets in the response. */
+
+ short max_an_rrsets; /*!< Allocated space for Answer RRsets. */
+ short max_ns_rrsets; /*!< Allocated space for Authority RRsets. */
+ short max_ar_rrsets; /*!< Allocated space for Additional RRsets. */
+
+ knot_opt_rr_t opt_rr; /*!< OPT RR included in the packet. */
+
+ uint8_t *wireformat; /*!< Wire format of the packet. */
+
+ short free_wireformat;
+ size_t parsed;
+
+ size_t size; /*!< Current wire size of the packet. */
+ size_t max_size; /*!< Maximum allowed size of the packet. */
+
+ /*! \brief Information needed for compressing domain names in packet. */
+ knot_compressed_dnames_t compression;
+
+ /*! \brief RRSets to be destroyed with the packet structure. */
+ const knot_rrset_t **tmp_rrsets;
+ short tmp_rrsets_count; /*!< Count of temporary RRSets. */
+ short tmp_rrsets_max; /*!< Allocated space for temporary RRSets. */
+
+ struct knot_packet *query; /*!< Associated query. */
+
+ knot_packet_prealloc_type_t prealloc_type;
+
+ size_t tsig_size; /*!< Space to reserve for the TSIG RR. */
+};
+
+typedef struct knot_packet knot_packet_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Default sizes for response structure parts and steps for increasing
+ * them.
+ */
+enum {
+ DEFAULT_ANCOUNT = 6, /*!< Default count of Answer RRSets. */
+ DEFAULT_NSCOUNT = 8, /*!< Default count of Authority RRSets. */
+ DEFAULT_ARCOUNT = 28, /*!< Default count of Additional RRSets. */
+
+ DEFAULT_ANCOUNT_QUERY = 1, /*!< Default count of Answer RRSets. */
+ DEFAULT_NSCOUNT_QUERY = 0, /*!< Default count of Authority RRSets. */
+ DEFAULT_ARCOUNT_QUERY = 1, /*!< Default count of Additional RRSets. */
+ /*!
+ * \brief Default count of all domain names in response.
+ *
+ * Used for compression table.
+ */
+ DEFAULT_DOMAINS_IN_RESPONSE = 22,
+
+ /*! \brief Default count of temporary RRSets stored in response. */
+ DEFAULT_TMP_RRSETS = 5,
+
+ /*! \brief Default count of temporary RRSets stored in query. */
+ DEFAULT_TMP_RRSETS_QUERY = 2,
+
+ STEP_ANCOUNT = 6, /*!< Step for increasing space for Answer RRSets. */
+ STEP_NSCOUNT = 8, /*!< Step for increasing space for Authority RRSets.*/
+ STEP_ARCOUNT = 8,/*!< Step for increasing space for Additional RRSets.*/
+ STEP_DOMAINS = 10, /*!< Step for resizing compression table. */
+ STEP_TMP_RRSETS = 5 /*!< Step for increasing temorary RRSets count. */
+};
+
+/*----------------------------------------------------------------------------*/
+#define PREALLOC_RRSETS(count) (count * sizeof(knot_rrset_t *))
+
+/*! \brief Sizes for preallocated space in the response structure. */
+enum {
+ /*! \brief Size of the response structure itself. */
+ PREALLOC_PACKET = sizeof(knot_packet_t),
+ /*! \brief Space for QNAME dname structure. */
+ PREALLOC_QNAME_DNAME = sizeof(knot_dname_t),
+ /*! \brief Space for QNAME name (maximum domain name size). */
+ PREALLOC_QNAME_NAME = 256,
+ /*! \brief Space for QNAME labels (maximum label count). */
+ PREALLOC_QNAME_LABELS = 127,
+ /*! \brief Total space for QNAME. */
+ PREALLOC_QNAME = PREALLOC_QNAME_DNAME
+ + PREALLOC_QNAME_NAME
+ + PREALLOC_QNAME_LABELS,
+ /*!
+ * \brief Space for RR owner wire format.
+ *
+ * Temporary buffer, used when putting RRSets to the response.
+ */
+ PREALLOC_RR_OWNER = 256,
+
+// /*! \brief Space for Answer RRSets. */
+// PREALLOC_ANSWER = DEFAULT_ANCOUNT * sizeof(knot_dname_t *),
+// /*! \brief Space for Authority RRSets. */
+// PREALLOC_AUTHORITY = DEFAULT_NSCOUNT * sizeof(knot_dname_t *),
+// /*! \brief Space for Additional RRSets. */
+// PREALLOC_ADDITIONAL = DEFAULT_ARCOUNT * sizeof(knot_dname_t *),
+// /*! \brief Total size for Answer, Authority and Additional RRSets. */
+// PREALLOC_RRSETS = PREALLOC_ANSWER
+// + PREALLOC_AUTHORITY
+// + PREALLOC_ADDITIONAL,
+ /*! \brief Space for one part of the compression table (domain names).*/
+ PREALLOC_DOMAINS =
+ DEFAULT_DOMAINS_IN_RESPONSE * sizeof(knot_dname_t *),
+ /*! \brief Space for other part of the compression table (offsets). */
+ PREALLOC_OFFSETS =
+ DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t),
+ PREALLOC_COMPRESSION = PREALLOC_DOMAINS + PREALLOC_OFFSETS,
+
+// /*! \brief Space for temporary RRSets. */
+// PREALLOC_TMP_RRSETS =
+// DEFAULT_TMP_RRSETS * sizeof(knot_rrset_t *),
+
+ PREALLOC_QUERY = PREALLOC_PACKET
+ + PREALLOC_QNAME
+ + PREALLOC_RRSETS(DEFAULT_ANCOUNT_QUERY)
+ + PREALLOC_RRSETS(DEFAULT_NSCOUNT_QUERY)
+ + PREALLOC_RRSETS(DEFAULT_ARCOUNT_QUERY)
+ + PREALLOC_RRSETS(DEFAULT_TMP_RRSETS_QUERY),
+
+ /*! \brief Total preallocated size for the response. */
+ PREALLOC_RESPONSE = PREALLOC_PACKET
+ + PREALLOC_QNAME
+ + PREALLOC_RR_OWNER
+ + PREALLOC_RRSETS(DEFAULT_ANCOUNT)
+ + PREALLOC_RRSETS(DEFAULT_NSCOUNT)
+ + PREALLOC_RRSETS(DEFAULT_ARCOUNT)
+ + PREALLOC_COMPRESSION
+ + PREALLOC_RRSETS(DEFAULT_TMP_RRSETS)
+};
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates new empty packet structure.
+ *
+ * \param prealloc What space should be preallocated in the structure.
+ *
+ * \return New packet structure or NULL if an error occured.
+ */
+knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc);
+
+/*!
+ * \brief Parses the DNS packet from wire format.
+ *
+ * \param packet Packet structure to parse into.
+ * \param wireformat Wire format of the DNS packet.
+ * \param size Size of the wire format in bytes.
+ * \param question_only Set to <> 0 if you do not want to parse the whole
+ * packet. In such case the parsing will end after the
+ * Question section. Set to 0 to parse the whole packet.
+ *
+ * \retval KNOT_EOK
+ */
+int knot_packet_parse_from_wire(knot_packet_t *packet,
+ const uint8_t *wireformat, size_t size,
+ int question_only);
+
+int knot_packet_parse_rest(knot_packet_t *packet);
+
+int knot_packet_parse_next_rr_answer(knot_packet_t *packet,
+ knot_rrset_t **rr);
+
+int knot_packet_parse_next_rr_additional(knot_packet_t *packet,
+ knot_rrset_t **rr);
+
+size_t knot_packet_size(const knot_packet_t *packet);
+
+/*! \brief Returns size of the wireformat of Header and Question sections. */
+size_t knot_packet_question_size(const knot_packet_t *packet);
+
+size_t knot_packet_parsed(const knot_packet_t *packet);
+
+/*!
+ * \brief Sets the maximum size of the packet and allocates space for wire
+ * format (if needed).
+ *
+ * This function also allocates space for the wireformat of the packet, if
+ * the given max size is larger than the current maximum size of the packet
+ * and copies the current wireformat over to the new space.
+ *
+ * \warning Do not call this function if you are not completely sure that the
+ * current wire format of the packet fits into the new space.
+ * It does not update the current size of the wire format, so the
+ * produced packet may be larger than the given max size.
+ *
+ * \param packet Packet to set the maximum size of.
+ * \param max_size Maximum size of the packet in bytes.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ *
+ * \todo Needs test.
+ */
+int knot_packet_set_max_size(knot_packet_t *packet, int max_size);
+
+uint16_t knot_packet_id(const knot_packet_t *packet);
+
+void knot_packet_set_id(knot_packet_t *packet, uint16_t id);
+
+void knot_packet_set_random_id(knot_packet_t *packet);
+
+/*!
+ * \brief Returns the OPCODE of the packet.
+ *
+ * \param packet Packet (with parsed query) to get the OPCODE from.
+ *
+ * \return OPCODE stored in the packet.
+ */
+uint8_t knot_packet_opcode(const knot_packet_t *packet);
+
+/*!
+ * \brief Returns the QNAME from the packet.
+ *
+ * \param packet Packet (with parsed query) to get the QNAME from.
+ *
+ * \return QNAME stored in the packet.
+ */
+const knot_dname_t *knot_packet_qname(const knot_packet_t *packet);
+
+/*!
+ * \brief Returns the QTYPE from the packet.
+ *
+ * \param packet Packet (with parsed query) to get the QTYPE from.
+ *
+ * \return QTYPE stored in the packet.
+ */
+uint16_t knot_packet_qtype(const knot_packet_t *packet);
+
+/*!
+ * \brief Set the QTYPE of the packet.
+ *
+ * \param packet Packet containing question.
+ * \param qtype New QTYPE for question.
+ */
+void knot_packet_set_qtype(knot_packet_t *packet, knot_rr_type_t qtype);
+
+
+/*!
+ * \brief Returns the QCLASS from the packet.
+ *
+ * \param response Packet (with parsed query) to get the QCLASS from.
+ *
+ * \return QCLASS stored in the packet.
+ */
+uint16_t knot_packet_qclass(const knot_packet_t *packet);
+
+int knot_packet_is_query(const knot_packet_t *packet);
+
+const knot_packet_t *knot_packet_query(const knot_packet_t *packet);
+
+int knot_packet_rcode(const knot_packet_t *packet);
+
+int knot_packet_tc(const knot_packet_t *packet);
+
+int knot_packet_qdcount(const knot_packet_t *packet);
+
+int knot_packet_ancount(const knot_packet_t *packet);
+
+int knot_packet_nscount(const knot_packet_t *packet);
+
+int knot_packet_arcount(const knot_packet_t *packet);
+
+void knot_packet_set_tsig_size(knot_packet_t *packet, size_t tsig_size);
+
+/*!
+ * \brief Returns number of RRSets in Answer section of the packet.
+ *
+ * \param response Packet to get the Answer RRSet count from.
+ */
+short knot_packet_answer_rrset_count(const knot_packet_t *packet);
+
+/*!
+ * \brief Returns number of RRSets in Authority section of the packet.
+ *
+ * \param response Packet to get the Authority RRSet count from.
+ */
+short knot_packet_authority_rrset_count(const knot_packet_t *packet);
+
+/*!
+ * \brief Returns number of RRSets in Additional section of the packet.
+ *
+ * \param response Packet to get the Additional RRSet count from.
+ */
+short knot_packet_additional_rrset_count(const knot_packet_t *packet);
+
+/*!
+ * \brief Returns the requested Answer RRset.
+ *
+ * \param packet Packet to get the RRSet from.
+ * \param pos Position of the RRSet in the Answer section (RRSets are stored
+ * in the order they were added to the response or parsed from the
+ * query).
+ *
+ * \return The RRSet on position \a pos in the Answer section of \a packet
+ * or NULL if there is no such RRSet.
+ */
+const knot_rrset_t *knot_packet_answer_rrset(
+ const knot_packet_t *packet, short pos);
+
+/*!
+ * \brief Returns the requested Authority RRset.
+ *
+ * \param packet Packet to get the RRSet from.
+ * \param pos Position of the RRSet in the Authority section (RRSets are stored
+ * in the order they were added to the response or parsed from the
+ * query).
+ *
+ * \return The RRSet on position \a pos in the Authority section of \a packet
+ * or NULL if there is no such RRSet.
+ */
+const knot_rrset_t *knot_packet_authority_rrset(
+ knot_packet_t *packet, short pos);
+
+/*!
+ * \brief Returns the requested Additional RRset.
+ *
+ * \param packet Packet to get the RRSet from.
+ * \param pos Position of the RRSet in the Additional section (RRSets are stored
+ * in the order they were added to the response or parsed from the
+ * query).
+ *
+ * \return The RRSet on position \a pos in the Additional section of \a packet
+ * or NULL if there is no such RRSet.
+ */
+const knot_rrset_t *knot_packet_additional_rrset(
+ knot_packet_t *packet, short pos);
+
+/*!
+ * \brief Checks if the packet already contains the given RRSet.
+ *
+ * It searches for the RRSet in the three lists of RRSets corresponding to
+ * Answer, Authority and Additional sections of the packet.
+ *
+ * \note Only pointers are compared, i.e. two instances of knot_rrset_t with
+ * the same data will be considered different.
+ *
+ * \param packet Packet to look for the RRSet in.
+ * \param rrset RRSet to look for.
+ *
+ * \retval 0 if \a resp does not contain \a rrset.
+ * \retval <> 0 if \a resp does contain \a rrset.
+ */
+int knot_packet_contains(const knot_packet_t *packet,
+ const knot_rrset_t *rrset,
+ knot_rrset_compare_type_t cmp);
+
+/*!
+ * \brief Adds RRSet to the list of temporary RRSets.
+ *
+ * Temporary RRSets are fully freed when the response structure is destroyed.
+ *
+ * \param response Response to which the temporary RRSet should be added.
+ * \param tmp_rrset Temporary RRSet to be stored in the response.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+int knot_packet_add_tmp_rrset(knot_packet_t *response,
+ knot_rrset_t *tmp_rrset);
+
+void knot_packet_free_tmp_rrsets(knot_packet_t *pkt);
+
+/*!
+ * \brief Converts the header structure to wire format.
+ *
+ * \note This function also adjusts the position (\a pos) according to
+ * the size of the converted wire format.
+ *
+ * \param[in] header DNS header structure to convert.
+ * \param[out] pos Position where to put the converted header. The space has
+ * to be allocated before calling this function.
+ * \param[out] size Size of the wire format of the header in bytes.
+ */
+void knot_packet_header_to_wire(const knot_header_t *header,
+ uint8_t **pos, size_t *size);
+
+int knot_packet_question_to_wire(knot_packet_t *packet);
+
+/*!
+ * \brief Converts the stored response OPT RR to wire format and adds it to
+ * the response wire format.
+ *
+ * \param resp Response structure.
+ */
+int knot_packet_edns_to_wire(knot_packet_t *packet);
+
+/*!
+ * \brief Converts the packet to wire format.
+ *
+ * \param packet Packet to be converted to wire format.
+ * \param wire Here the wire format of the packet will be stored.
+ * Space for the packet will be allocated. *resp_wire must
+ * be set to NULL (to avoid leaks).
+ * \param wire_size The size of the packet in wire format will be stored here.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ */
+int knot_packet_to_wire(knot_packet_t *packet, uint8_t **wire,
+ size_t *wire_size);
+
+const uint8_t *knot_packet_wireformat(const knot_packet_t *packet);
+
+/*!
+ * \brief Properly destroys the packet structure.
+ *
+ * \param response Packet to be destroyed.
+ */
+void knot_packet_free(knot_packet_t **packet);
+
+/*!
+ * \brief Dumps the whole packet in human-readable form.
+ *
+ * \note This function is empty unless KNOT_PACKET_DEBUG is defined.
+ *
+ * \param resp Packet to dump.
+ */
+void knot_packet_dump(const knot_packet_t *packet);
+
+#endif /* _KNOT_PACKET_H_ */
+
+/*! @} */
diff --git a/src/libknot/packet/query.c b/src/libknot/packet/query.c
new file mode 100644
index 0000000..63e902a
--- /dev/null
+++ b/src/libknot/packet/query.c
@@ -0,0 +1,228 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include "packet/query.h"
+
+#include "util/error.h"
+#include "util/wire.h"
+
+/*----------------------------------------------------------------------------*/
+
+int knot_query_rr_to_wire(const knot_rrset_t *rrset, const knot_rdata_t *rdata,
+ uint8_t **wire, uint8_t *endp)
+{
+ /* Store owner. */
+ knot_dname_t *owner = rrset->owner;
+ if (*wire + owner->size > endp) {
+ return KNOT_ENOMEM;
+ }
+ memcpy(*wire, owner->name, owner->size);
+ *wire += owner->size;
+
+ if (*wire + 10 > endp) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Write RR header. */
+ knot_wire_write_u16(*wire, rrset->type); *wire += 2;
+ knot_wire_write_u16(*wire, rrset->rclass); *wire += 2;
+ knot_wire_write_u32(*wire, rrset->ttl); *wire += 4;
+ knot_wire_write_u16(*wire, 0); *wire += 2; /* RDLENGTH reserve. */
+ uint8_t *rdlength_p = *wire - 2;
+ uint16_t rdlength = 0;
+
+ /* Write data. */
+ knot_dname_t *dname = 0;
+ uint16_t *raw_data = 0;
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+
+ for (int i = 0; i < rdata->count; ++i) {
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+
+ /* Check space for dname. */
+ dname = knot_rdata_item(rdata, i)->dname;
+ if (*wire + dname->size > endp) {
+ return KNOT_ESPACE;
+ }
+
+ /* Save domain name. */
+ memcpy(*wire, dname->name, dname->size);
+ *wire += dname->size;
+ rdlength += dname->size;
+ break;
+ default:
+ raw_data = knot_rdata_item(rdata, i)->raw_data;
+ if (*wire + raw_data[0] > endp) {
+ return KNOT_ESPACE;
+ }
+
+ /* Copy data. */
+ memcpy(*wire, raw_data + 1, raw_data[0]);
+ *wire += raw_data[0];
+ rdlength += raw_data[0];
+ break;
+
+ }
+ }
+
+ /* Store rdlength. */
+ knot_wire_write_u16(rdlength_p, rdlength);
+
+ return KNOT_EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+int knot_query_dnssec_requested(const knot_packet_t *query)
+{
+ if (query == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return ((knot_edns_get_version(&query->opt_rr) != EDNS_NOT_SUPPORTED)
+ && knot_edns_do(&query->opt_rr));
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_query_nsid_requested(const knot_packet_t *query)
+{
+ if (query == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return ((knot_edns_get_version(&query->opt_rr) != EDNS_NOT_SUPPORTED)
+ && knot_edns_has_option(&query->opt_rr, EDNS_OPTION_NSID));
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_query_edns_supported(const knot_packet_t *query)
+{
+ if (query == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return (knot_edns_get_version(&query->opt_rr) != EDNS_NOT_SUPPORTED);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_query_init(knot_packet_t *query)
+{
+ if (query == NULL) {
+ return KNOT_EBADARG;
+ }
+ // set the qr bit to 0
+ knot_wire_flags_clear_qr(&query->header.flags1);
+
+ uint8_t *pos = query->wireformat;
+ knot_packet_header_to_wire(&query->header, &pos, &query->size);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_query_set_question(knot_packet_t *query,
+ const knot_question_t *question)
+{
+ if (query == NULL || question == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ query->question.qname = question->qname;
+ query->question.qclass = question->qclass;
+ query->question.qtype = question->qtype;
+ query->header.qdcount = 1;
+
+ // convert the Question to wire format right away
+ knot_packet_question_to_wire(query);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_query_set_opcode(knot_packet_t *query, uint8_t opcode)
+{
+ if (query == NULL) {
+ return KNOT_EBADARG;
+ }
+ // set the OPCODE in the structure
+ knot_wire_flags_set_opcode(&query->header.flags1, opcode);
+ // set the OPCODE in the wire format
+ knot_wire_set_opcode(query->wireformat, opcode);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_query_add_rrset_authority(knot_packet_t *query,
+ const knot_rrset_t *rrset)
+{
+ if (query == NULL || rrset == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ if (query->ns_rrsets == query->max_ns_rrsets) {
+ size_t oldsize = query->max_ns_rrsets * sizeof(knot_rrset_t *);
+ ++query->max_ns_rrsets;
+ size_t newsize = query->max_ns_rrsets * sizeof(knot_rrset_t *);
+ const knot_rrset_t ** na = malloc(newsize);
+ if (na == 0) {
+ query->max_ns_rrsets = 0;
+ return KNOT_ENOMEM;
+ } else {
+ memcpy(na, query->authority, oldsize);
+ free(query->authority);
+ query->authority = na;
+ }
+ }
+
+ /* Append to packet. */
+ query->authority[query->ns_rrsets] = rrset;
+
+ /* Write to wire. */
+ uint8_t *startp = query->wireformat + query->size;
+ uint8_t *endp = query->wireformat + query->max_size;
+
+ assert(endp - startp > query->opt_rr.size + query->tsig_size);
+ // reserve space for OPT RR
+ endp -= query->opt_rr.size;
+ /*! \note [TSIG] reserve space for TSIG RR */
+ endp -= query->tsig_size;
+
+ uint8_t *pos = startp;
+
+ const knot_rdata_t *rdata = 0;
+ while ((rdata = knot_rrset_rdata_next(rrset, rdata))) {
+ knot_query_rr_to_wire(rrset, rdata, &pos, endp);
+ }
+
+ size_t written = (pos - startp);
+ query->size += written;
+ ++query->ns_rrsets;
+ ++query->header.nscount;
+
+ return KNOT_EOK;
+}
+
diff --git a/src/libknot/packet/query.h b/src/libknot/packet/query.h
new file mode 100644
index 0000000..a979641
--- /dev/null
+++ b/src/libknot/packet/query.h
@@ -0,0 +1,93 @@
+/*!
+ * \file query.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief API for manipulating queries.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_QUERY_H_
+#define _KNOT_QUERY_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "packet/packet.h"
+#include "dname.h"
+#include "rrset.h"
+#include "edns.h"
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Checks if DNSSEC was requested in the query (i.e. the DO bit was set).
+ *
+ * \param query Packet where the parsed query is stored.
+ *
+ * \retval 0 if the DO bit was not set in the query, or the query is not yet
+ * parsed.
+ * \retval > 0 if DO bit was set in the query.
+ */
+int knot_query_dnssec_requested(const knot_packet_t *query);
+
+/*!
+ * \brief Checks if NSID was requested in the query (i.e. the NSID option was
+ * present in the query OPT RR).
+ *
+ * \param query Packet where the parsed query is stored.
+ *
+ * \retval 0 if the NSID option was not present in the query, or the query is
+ * not yet parsed.
+ * \retval > 0 if the NSID option was present in the query.
+ */
+int knot_query_nsid_requested(const knot_packet_t *query);
+
+int knot_query_edns_supported(const knot_packet_t *query);
+
+//int knot_query_set_qname(knot_packet_t *query, const knot_dname_t *qname);
+
+//int knot_query_set_qtype(knot_packet_t *query, uint16_t qtype);
+
+//int knot_query_set_qclass(knot_packet_t *query, uint16_t qclass);
+
+int knot_query_init(knot_packet_t *query);
+
+int knot_query_set_question(knot_packet_t *query,
+ const knot_question_t *question);
+
+int knot_query_set_opcode(knot_packet_t *query, uint8_t opcode);
+
+/*!
+ * \brief Adds a RRSet to the Authority section of the query.
+ *
+ * \param query Query to add the RRSet into.
+ * \param rrset RRSet to be added.
+ *
+ * \retval KNOT_EOK if successful, or the RRSet was already in the query.
+ * \retval KNOT_ENOMEM
+ * \retval KNOT_ESPACE
+ */
+int knot_query_add_rrset_authority(knot_packet_t *query,
+ const knot_rrset_t *rrset);
+
+
+#endif /* _KNOT_QUERY_H_ */
+
+/*! @} */
diff --git a/src/libknot/packet/response.c b/src/libknot/packet/response.c
new file mode 100644
index 0000000..e6f89d0
--- /dev/null
+++ b/src/libknot/packet/response.c
@@ -0,0 +1,1170 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#include "packet/response.h"
+#include "util/wire.h"
+#include "util/descriptor.h"
+#include "common.h"
+#include "util/error.h"
+#include "util/debug.h"
+#include "packet/packet.h"
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Holds information about compressed domain name.
+ *
+ * Used only to pass information between functions.
+ *
+ * \todo This description should be revised and clarified.
+ */
+struct knot_compr_owner {
+ /*!
+ * \brief Place where the name is stored in the wire format of the
+ * packet.
+ */
+ uint8_t *wire;
+ short size; /*!< Size of the domain name in bytes. */
+ /*! \brief Position of the name relative to the start of the packet. */
+ size_t pos;
+};
+
+typedef struct knot_compr_owner knot_compr_owner_t;
+
+/*!
+ * \brief Holds information about compressed domain names in packet.
+ *
+ * Used only to pass information between functions.
+ *
+ * \todo This description should be revised and clarified.
+ */
+struct knot_compr {
+ knot_compressed_dnames_t *table; /*!< Compression table. */
+ size_t wire_pos; /*!< Current position in the wire format. */
+ knot_compr_owner_t owner; /*!< Information about the current name. */
+};
+
+typedef struct knot_compr knot_compr_t;
+
+static const size_t KNOT_RESPONSE_MAX_PTR = 16383;
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Reallocates space for compression table.
+ *
+ * \param table Compression table to reallocate space for.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+static int knot_response_realloc_compr(knot_compressed_dnames_t *table)
+{
+ int free_old = table->max != DEFAULT_DOMAINS_IN_RESPONSE;
+ size_t *old_offsets = table->offsets;
+ const knot_dname_t **old_dnames = table->dnames;
+
+ short new_max_count = table->max + STEP_DOMAINS;
+
+ size_t *new_offsets = (size_t *)malloc(new_max_count * sizeof(size_t));
+ CHECK_ALLOC_LOG(new_offsets, -1);
+
+ const knot_dname_t **new_dnames = (const knot_dname_t **)malloc(
+ new_max_count * sizeof(knot_dname_t *));
+ if (new_dnames == NULL) {
+ ERR_ALLOC_FAILED;
+ free(new_offsets);
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(new_offsets, table->offsets, table->max * sizeof(size_t));
+ memcpy(new_dnames, table->dnames,
+ table->max * sizeof(knot_dname_t *));
+
+ table->offsets = new_offsets;
+ table->dnames = new_dnames;
+ table->max = new_max_count;
+
+ if (free_old) {
+ free(old_offsets);
+ free(old_dnames);
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Stores new mapping between domain name and offset in the compression
+ * table.
+ *
+ * If the domain name is already present in the table, it is not inserted again.
+ *
+ * \param table Compression table to save the mapping into.
+ * \param dname Domain name to insert.
+ * \param pos Position of the domain name in the packet's wire format.
+ */
+static void knot_response_compr_save(knot_compressed_dnames_t *table,
+ const knot_dname_t *dname, size_t pos)
+{
+ assert(table->count < table->max);
+
+ for (int i = 0; i < table->count; ++i) {
+ if (table->dnames[i] == dname) {
+ dbg_response("Already present, skipping..\n");
+ return;
+ }
+ }
+
+ table->dnames[table->count] = dname;
+ table->offsets[table->count] = pos;
+ ++table->count;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Stores domain name position and positions of its parent domain names
+ * to the compression table.
+ *
+ * If part of the domain name (\a dname) was not found previously in the
+ * compression table, this part and all its parent domains is stored also, to
+ * maximize compression potential.
+ *
+ * \param table Compression table to save the information into.
+ * \param dname Domain name to save.
+ * \param not_matched Count of labels not matched when previously searching in
+ * the compression table for \a dname.
+ * \param pos Position of the domain name in the wire format of the packet.
+ * \param unmatched_offset Position of the unmatched parent domain of \a dname.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+static int knot_response_store_dname_pos(knot_compressed_dnames_t *table,
+ const knot_dname_t *dname,
+ int not_matched, size_t pos,
+ size_t unmatched_offset,
+ int compr_cs)
+{
+dbg_response_exec(
+ char *name = knot_dname_to_str(dname);
+ dbg_response("Putting dname %s into compression table."
+ " Labels not matched: %d, position: %zu,"
+ ", pointer: %p, unmatched off: %zu\n", name,
+ not_matched, pos, dname, unmatched_offset);
+ free(name);
+);
+ if (pos > KNOT_RESPONSE_MAX_PTR) {
+ dbg_response("Pointer larger than it can be, not"
+ " saving\n");
+ return KNOT_EDNAMEPTR;
+ }
+
+ if (table->count == table->max &&
+ knot_response_realloc_compr(table) != 0) {
+ return KNOT_ENOMEM;
+ }
+
+ // store the position of the name
+// table->dnames[table->count] = dname;
+// table->offsets[table->count] = pos;
+// ++table->count;
+
+ /*
+ * Store positions of ancestors if more than 1 label was not matched.
+ *
+ * In case the name is not in the zone, the counting to not_matched
+ * may be limiting, because the search stopped before after the first
+ * label (i.e. not_matched == 1). So we do not store the parents in
+ * this case. However, storing them will require creating those domain
+ * names, as they do not exist.
+ *
+ * The same problem is with domain names synthetized from wildcards.
+ * These also do not have any node to follow.
+ *
+ * We accept this as performance has higher
+ * priority than the best possible compression.
+ */
+ const knot_dname_t *to_save = dname;
+ size_t parent_pos = pos;
+ int i = 0;
+
+ while (to_save != NULL && i < knot_dname_label_count(dname)) {
+ if (i == not_matched) {
+ parent_pos = unmatched_offset;
+ }
+
+dbg_response_exec(
+ char *name = knot_dname_to_str(to_save);
+ dbg_response("Putting dname %s into compression table."
+ " Position: %zu, pointer: %p\n",
+ name, parent_pos, to_save);
+ free(name);
+);
+
+ if (table->count == table->max &&
+ knot_response_realloc_compr(table) != 0) {
+ dbg_response("Unable to realloc.\n");
+ return KNOT_ENOMEM;
+ }
+
+// dbg_response("Saving..\n");
+ knot_response_compr_save(table, to_save, parent_pos);
+
+ /*! \todo Remove '!compr_cs'. */
+ // This is a temporary hack to avoid the wrong behaviour
+ // when the wrong not_matched count is used to compare with i
+ // and resulting in using the 0 offset.
+ // If case-sensitive search is in place, we should not save the
+ // node's parent's positions.
+
+ to_save = !compr_cs && (knot_dname_node(to_save, 1) != NULL
+ && knot_node_parent(knot_dname_node(to_save, 1), 1)
+ != NULL) ? knot_node_owner(knot_node_parent(
+ knot_dname_node(to_save, 1), 1))
+ : NULL;
+
+ dbg_response("i: %d\n", i);
+ parent_pos += knot_dname_label_size(dname, i) + 1;
+// parent_pos += (i > 0)
+// ? knot_dname_label_size(dname, i - 1) + 1 : 0;
+ ++i;
+ }
+
+ return KNOT_EOK;
+}
+
+/*---------------------------------------------------------------------------*/
+/*!
+ * \brief Tries to find offset of domain name in the compression table.
+ *
+ * \param table Compression table to search in.
+ * \param dname Domain name to search for.
+ * \param compr_cs Set to <> 0 if dname compression should use case sensitive
+ * comparation. Set to 0 otherwise.
+ *
+ * \return Offset of \a dname stored in the compression table or -1 if the name
+ * was not found in the table.
+ */
+static size_t knot_response_find_dname_pos(
+ const knot_compressed_dnames_t *table,
+ const knot_dname_t *dname, int compr_cs)
+{
+ for (int i = 0; i < table->count; ++i) {
+// dbg_response("Comparing dnames %p and %p\n",
+// dname, table->dnames[i]);
+//dbg_response_exec(
+// char *name = knot_dname_to_str(dname);
+// dbg_response("(%s and ", name);
+// name = knot_dname_to_str(table->dnames[i]);
+// dbg_response("%s)\n", name);
+// free(name);
+//);
+ //if (table->dnames[i] == dname) {
+ int ret = (compr_cs)
+ ? knot_dname_compare_cs(table->dnames[i], dname)
+ : knot_dname_compare(table->dnames[i], dname);
+ if (ret == 0) {
+ dbg_response("Found offset: %zu\n",
+ table->offsets[i]);
+ return table->offsets[i];
+ }
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/*!
+ * \brief Put a compressed domain name to the wire format of the packet.
+ *
+ * Puts the not matched part of the domain name to the wire format and puts
+ * a pointer to the rest of the name after that.
+ *
+ * \param dname Domain name to put to the wire format.
+ * \param not_matched Size of the part of domain name that cannot be compressed.
+ * \param offset Position of the rest of the domain name in the packet's wire
+ * format.
+ * \param wire Place where to put the wire format of the name.
+ * \param max Maximum available size of the place for the wire format.
+ *
+ * \return Size of the compressed domain name put into the wire format or
+ * KNOT_ESPACE if it did not fit.
+ */
+static int knot_response_put_dname_ptr(const knot_dname_t *dname,
+ int not_matched, size_t offset,
+ uint8_t *wire, size_t max)
+{
+ // put the not matched labels
+ short size = knot_dname_size_part(dname, not_matched);
+ if (size + 2 > max) {
+ return KNOT_ESPACE;
+ }
+
+ memcpy(wire, knot_dname_name(dname), size);
+ knot_wire_put_pointer(wire + size, offset);
+
+ dbg_response("Size of the dname with ptr: %d\n", size + 2);
+
+ return size + 2;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tries to compress domain name and creates its wire format.
+ *
+ * \param dname Domain name to convert and compress.
+ * \param compr Compression table holding information about offsets of domain
+ * names in the packet.
+ * \param dname_wire Place where to put the wire format of the name.
+ * \param max Maximum available size of the place for the wire format.
+ * \param compr_cs Set to <> 0 if dname compression should use case sensitive
+ * comparation. Set to 0 otherwise.
+ *
+ * \return Size of the domain name's wire format or KNOT_ESPACE if it did not
+ * fit into the provided space.
+ */
+static int knot_response_compress_dname(const knot_dname_t *dname,
+ knot_compr_t *compr, uint8_t *dname_wire, size_t max, int compr_cs)
+{
+ int size = 0;
+ /*!
+ * \todo Compress!!
+ *
+ * if pos == 0, do not store the position!
+ */
+
+ // try to find the name or one of its ancestors in the compr. table
+#ifdef COMPRESSION_PEDANTIC
+ //knot_dname_t *to_find = knot_dname_copy(dname);
+ knot_dname_t *to_find = (knot_dname_t *)dname;
+ int copied = 0;
+#else
+ const knot_dname_t *to_find = dname;
+#endif
+ size_t offset = 0;
+ int not_matched = 0;
+
+ while (to_find != NULL && knot_dname_label_count(to_find) != 0) {
+dbg_response_exec(
+ char *name = knot_dname_to_str(to_find);
+ dbg_response("Searching for name %s in the compression"
+ " table, not matched labels: %d\n", name,
+ not_matched);
+ free(name);
+);
+ offset = knot_response_find_dname_pos(compr->table, to_find,
+ compr_cs);
+ if (offset == 0) {
+ ++not_matched;
+ } else {
+ break;
+ }
+#ifdef COMPRESSION_PEDANTIC
+ if (compr_cs || to_find->node == NULL
+ || to_find->node->owner != to_find
+ || to_find->node->parent == NULL) {
+ if (!copied) {
+ to_find = knot_dname_left_chop(to_find);
+ copied = 1;
+ } else {
+ knot_dname_left_chop_no_copy(to_find);
+ }
+ } else {
+ assert(to_find->node != to_find->node->parent);
+ assert(to_find != to_find->node->parent->owner);
+ to_find = to_find->node->parent->owner;
+ }
+#else
+ // if case-sensitive comparation, we cannot just take the parent
+ if (compr_cs || knot_dname_node(to_find, 1) == NULL
+ || knot_node_owner(knot_dname_node(to_find, 1)) != to_find
+ || knot_node_parent(knot_dname_node(to_find, 1), 1)
+ == NULL) {
+ dbg_response("compr_cs: %d\n", compr_cs);
+ dbg_response("knot_dname_node(to_find, 1) == %p"
+ "\n", knot_dname_node(to_find, 1));
+
+ if (knot_dname_node(to_find, 1) != NULL) {
+ dbg_response("knot_node_owner(knot_dname_node("
+ "to_find, 1)) = %p, to_find = %p\n",
+ knot_node_owner(knot_dname_node(to_find, 1)),
+ to_find);
+ dbg_response("knot_node_parent(knot_dname_node("
+ "to_find, 1), 1) = %p\n",
+ knot_node_parent(knot_dname_node(to_find, 1), 1));
+ }
+ break;
+ } else {
+ assert(knot_dname_node(to_find, 1) !=
+ knot_node_parent(knot_dname_node(to_find, 1), 1));
+ assert(to_find != knot_node_owner(
+ knot_node_parent(knot_dname_node(to_find, 1), 1)));
+ to_find = knot_node_owner(
+ knot_node_parent(knot_dname_node(to_find, 1), 1));
+ dbg_response("New to_find: %p\n", to_find);
+ }
+#endif
+ }
+
+#ifdef COMPRESSION_PEDANTIC
+ if (copied) {
+ knot_dname_free(&to_find);
+ }
+#endif
+
+ dbg_response("Max size available for domain name: %zu\n", max);
+
+ if (offset > 0) { // found such dname somewhere in the packet
+ dbg_response("Found name in the compression table.\n");
+ assert(offset >= KNOT_WIRE_HEADER_SIZE);
+ size = knot_response_put_dname_ptr(dname, not_matched, offset,
+ dname_wire, max);
+ if (size <= 0) {
+ return KNOT_ESPACE;
+ }
+ } else {
+ dbg_response("Not found, putting whole name.\n");
+ // now just copy the dname without compressing
+ if (dname->size > max) {
+ return KNOT_ESPACE;
+ }
+
+ memcpy(dname_wire, dname->name, dname->size);
+ size = dname->size;
+ }
+
+ // in either way, put info into the compression table
+ /*! \todo This is useless if the name was already in the table.
+ * It is meaningful only if the found name is the one from QNAME
+ * and thus its parents are not stored yet.
+ */
+ assert(compr->wire_pos >= 0);
+
+ if (knot_response_store_dname_pos(compr->table, dname, not_matched,
+ compr->wire_pos, offset, compr_cs)
+ != 0) {
+ dbg_response("Compression info could not be stored."
+ "\n");
+ }
+
+ return size;
+}
+
+/*---------------------------------------------------------------------------*/
+/*!
+ * \brief Convert one RR into wire format.
+ *
+ * \param[in] rrset RRSet to which the RR belongs.
+ * \param[in] rdata The actual RDATA of this RR.
+ * \param[in] compr Information about compressed domain names in the packet.
+ * \param[out] rrset_wire Place to put the wire format of the RR into.
+ * \param[in] max_size Size of space available for the wire format.
+ * \param[in] compr_cs Set to <> 0 if dname compression should use case
+ * sensitive comparation. Set to 0 otherwise.
+ *
+ * \return Size of the RR's wire format or KNOT_ESPACE if it did not fit into
+ * the provided space.
+ */
+static int knot_response_rr_to_wire(const knot_rrset_t *rrset,
+ const knot_rdata_t *rdata,
+ knot_compr_t *compr,
+ uint8_t **rrset_wire, size_t max_size,
+ int compr_cs)
+{
+ int size = 0;
+
+ dbg_response("Max size: %zu, owner pos: %zu, owner size: %d\n",
+ max_size, compr->owner.pos, compr->owner.size);
+
+ if (size + ((compr->owner.pos == 0
+ || compr->owner.pos > KNOT_RESPONSE_MAX_PTR)
+ ? compr->owner.size : 2) + 10
+ > max_size) {
+ return KNOT_ESPACE;
+ }
+
+ dbg_response("Owner position: %zu\n", compr->owner.pos);
+
+ // put owner if needed (already compressed)
+ if (compr->owner.pos == 0 || compr->owner.pos > KNOT_RESPONSE_MAX_PTR) {
+ memcpy(*rrset_wire, compr->owner.wire, compr->owner.size);
+ compr->owner.pos = compr->wire_pos;
+ *rrset_wire += compr->owner.size;
+ size += compr->owner.size;
+ } else {
+ dbg_response("Putting pointer: %zu\n",
+ compr->owner.pos);
+ knot_wire_put_pointer(*rrset_wire, compr->owner.pos);
+ *rrset_wire += 2;
+ size += 2;
+ }
+
+ dbg_response("Max size: %zu, size: %d\n", max_size, size);
+
+ dbg_response("Wire format:\n");
+
+ // put rest of RR 'header'
+ knot_wire_write_u16(*rrset_wire, rrset->type);
+ dbg_response(" Type: %u\n", rrset->type);
+ dbg_response(" Type in wire: ");
+ dbg_response_hex((char *)*rrset_wire, 2);
+ *rrset_wire += 2;
+
+ knot_wire_write_u16(*rrset_wire, rrset->rclass);
+ dbg_response(" Class: %u\n", rrset->rclass);
+ dbg_response(" Class in wire: ");
+ dbg_response_hex((char *)*rrset_wire, 2);
+ *rrset_wire += 2;
+
+ knot_wire_write_u32(*rrset_wire, rrset->ttl);
+ dbg_response(" TTL: %u\n", rrset->ttl);
+ dbg_response(" TTL in wire: ");
+ dbg_response_hex((char *)*rrset_wire, 4);
+ *rrset_wire += 4;
+
+ // save space for RDLENGTH
+ uint8_t *rdlength_pos = *rrset_wire;
+ *rrset_wire += 2;
+
+ size += 10;
+ compr->wire_pos += size;
+
+ dbg_response("Max size: %zu, size: %d\n", max_size, size);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+
+ uint16_t rdlength = 0;
+
+ for (int i = 0; i < rdata->count; ++i) {
+ if (max_size < size + rdlength) {
+ return KNOT_ESPACE;
+ }
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME: {
+ int ret = knot_response_compress_dname(
+ knot_rdata_item(rdata, i)->dname,
+ compr, *rrset_wire, max_size - size - rdlength,
+ compr_cs);
+
+ if (ret < 0) {
+ return KNOT_ESPACE;
+ }
+
+ dbg_response("Compressed dname size: %d\n",
+ ret);
+ *rrset_wire += ret;
+ rdlength += ret;
+ compr->wire_pos += ret;
+ // TODO: compress domain name
+ break;
+ }
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME: {
+ knot_dname_t *dname =
+ knot_rdata_item(rdata, i)->dname;
+ if (size + rdlength + dname->size > max_size) {
+ return KNOT_ESPACE;
+ }
+
+ // save whole domain name
+ memcpy(*rrset_wire, dname->name, dname->size);
+ dbg_response("Uncompressed dname size: %d\n",
+ dname->size);
+ *rrset_wire += dname->size;
+ rdlength += dname->size;
+ compr->wire_pos += dname->size;
+ break;
+ }
+// case KNOT_RDATA_WF_BINARYWITHLENGTH: {
+// uint16_t *raw_data =
+// knot_rdata_item(rdata, i)->raw_data;
+
+// if (size + raw_data[0] + 1 > max_size) {
+// return KNOT_ESPACE;
+// }
+
+// // copy also the rdata item size
+// assert(raw_data[0] < 256);
+// **rrset_wire = raw_data[0];
+// *rrset_wire += 1;
+// memcpy(*rrset_wire, raw_data + 1, raw_data[0]);
+// dbg_response("Raw data size: %d\n",
+// raw_data[0] + 1);
+// *rrset_wire += raw_data[0];
+// rdlength += raw_data[0] + 1;
+// compr->wire_pos += raw_data[0] + 1;
+// break;
+// }
+ default: {
+ uint16_t *raw_data =
+ knot_rdata_item(rdata, i)->raw_data;
+
+ if (size + rdlength + raw_data[0] > max_size) {
+ return KNOT_ESPACE;
+ }
+
+ // copy just the rdata item data (without size)
+ memcpy(*rrset_wire, raw_data + 1, raw_data[0]);
+ dbg_response("Raw data size: %d\n",
+ raw_data[0]);
+ *rrset_wire += raw_data[0];
+ rdlength += raw_data[0];
+ compr->wire_pos += raw_data[0];
+ break;
+ }
+ }
+ }
+
+ dbg_response("Max size: %zu, size: %d\n", max_size, size);
+
+ assert(size + rdlength <= max_size);
+ size += rdlength;
+ knot_wire_write_u16(rdlength_pos, rdlength);
+
+ return size;
+}
+
+/*---------------------------------------------------------------------------*/
+/*!
+ * \brief Convert whole RRSet into wire format.
+ *
+ * \param[in] rrset RRSet to convert
+ * \param[out] pos Place where to put the wire format.
+ * \param[out] size Size of the converted wire format.
+ * \param[in] max_size Maximum available space for the wire format.
+ * \param wire_pos Current position in the wire format of the whole packet.
+ * \param owner_tmp Wire format of the RRSet's owner, possibly compressed.
+ * \param compr Information about compressed domain names in the packet.
+ * \param compr_cs Set to <> 0 if dname compression should use case sensitive
+ * comparation. Set to 0 otherwise.
+ *
+ * \return Size of the RRSet's wire format or KNOT_ESPACE if it did not fit
+ * into the provided space.
+ */
+static int knot_response_rrset_to_wire(const knot_rrset_t *rrset,
+ uint8_t **pos, size_t *size,
+ size_t max_size, size_t wire_pos,
+ uint8_t *owner_tmp,
+ knot_compressed_dnames_t *compr,
+ int compr_cs)
+{
+dbg_response_exec(
+ char *name = knot_dname_to_str(rrset->owner);
+ dbg_response("Converting RRSet with owner %s, type %s\n",
+ name, knot_rrtype_to_string(rrset->type));
+ free(name);
+ dbg_response(" Size before: %zu\n", *size);
+);
+
+ // if no RDATA in RRSet, return
+ if (rrset->rdata == NULL) {
+ return KNOT_EOK;
+ }
+
+ //uint8_t *rrset_wire = (uint8_t *)malloc(PREALLOC_RRSET_WIRE);
+ //short rrset_size = 0;
+
+ //uint8_t *owner_wire = (uint8_t *)malloc(rrset->owner->size);
+ /*
+ * We may pass the current position to the compression function
+ * because if the owner will be put somewhere, it will be on the
+ * current position (first item of a RR). If it will not be put into
+ * the wireformat, we may remove the dname (and possibly its parents)
+ * from the compression table.
+ */
+
+ knot_compr_t compr_info;
+ //compr_info.new_entries = 0;
+ compr_info.table = compr;
+ compr_info.wire_pos = wire_pos;
+ compr_info.owner.pos = 0;
+ compr_info.owner.wire = owner_tmp;
+ compr_info.owner.size =
+ knot_response_compress_dname(rrset->owner, &compr_info,
+ owner_tmp, max_size, compr_cs);
+
+ dbg_response(" Owner size: %d, position: %zu\n",
+ compr_info.owner.size, compr_info.owner.pos);
+ if (compr_info.owner.size < 0) {
+ return KNOT_ESPACE;
+ }
+
+ int rrs = 0;
+ short rrset_size = 0;
+
+ const knot_rdata_t *rdata = rrset->rdata;
+ do {
+ int ret = knot_response_rr_to_wire(rrset, rdata, &compr_info,
+ pos, max_size - rrset_size,
+ compr_cs);
+
+ assert(ret != 0);
+
+ if (ret < 0) {
+ // some RR didn't fit in, so no RRs should be used
+ // TODO: remove last entries from compression table
+ dbg_response("Some RR didn't fit in.\n");
+ return KNOT_ESPACE;
+ }
+
+ dbg_response("RR of size %d added.\n", ret);
+ rrset_size += ret;
+ ++rrs;
+ } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL);
+
+ //memcpy(*pos, rrset_wire, rrset_size);
+ //*size += rrset_size;
+ //*pos += rrset_size;
+
+ // the whole RRSet did fit in
+ assert (rrset_size <= max_size);
+ *size += rrset_size;
+
+ dbg_response(" Size after: %zu\n", *size);
+
+ return rrs;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tries to add RRSet to the response.
+ *
+ * This function tries to convert the RRSet to wire format and add it to the
+ * wire format of the response and if successful, adds the RRSet to the given
+ * list (and updates its size). If the RRSet did not fit into the available
+ * space (\a max_size), it is omitted as a whole and the TC bit may be set
+ * (according to \a tc).
+ *
+ * \param rrsets Lists of RRSets to which this RRSet should be added.
+ * \param rrset_count Number of RRSets in the list.
+ * \param resp Response structure where the RRSet should be added.
+ * \param max_size Maximum available space in wire format of the response.
+ * \param rrset RRSet to add.
+ * \param tc Set to <> 0 if omitting the RRSet should cause the TC bit to be
+ * set in the response.
+ * \param compr_cs Set to <> 0 if dname compression should use case sensitive
+ * comparation. Set to 0 otherwise.
+ *
+ * \return Count of RRs added to the response or KNOT_ESPACE if the RRSet did
+ * not fit in the available space.
+ */
+static int knot_response_try_add_rrset(const knot_rrset_t **rrsets,
+ short *rrset_count,
+ knot_packet_t *resp,
+ size_t max_size,
+ const knot_rrset_t *rrset, int tc,
+ int compr_cs)
+{
+ //short size = knot_response_rrset_size(rrset, &resp->compression);
+
+dbg_response_exec(
+ char *name = knot_dname_to_str(rrset->owner);
+ dbg_response("\nAdding RRSet with owner %s and type %s: \n",
+ name, knot_rrtype_to_string(rrset->type));
+ free(name);
+);
+
+ uint8_t *pos = resp->wireformat + resp->size;
+ size_t size = 0;
+ int rrs = knot_response_rrset_to_wire(rrset, &pos, &size, max_size,
+ resp->size, resp->owner_tmp,
+ &resp->compression, compr_cs);
+
+ if (rrs >= 0) {
+ rrsets[(*rrset_count)++] = rrset;
+ resp->size += size;
+ dbg_response("RRset added, size: %zu, RRs: %d, total "
+ "size of response: %zu\n\n", size, rrs,
+ resp->size);
+ } else if (tc) {
+ dbg_response("Setting TC bit.\n");
+ knot_wire_flags_set_tc(&resp->header.flags1);
+ knot_wire_set_tc(resp->wireformat);
+ }
+
+ return rrs;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Reallocate space for RRSets.
+ *
+ * \param rrsets Space for RRSets.
+ * \param max_count Size of the space available for the RRSets.
+ * \param default_max_count Size of the space pre-allocated for the RRSets when
+ * the response structure was initialized.
+ * \param step How much the space should be increased.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+static int knot_response_realloc_rrsets(const knot_rrset_t ***rrsets,
+ short *max_count,
+ short default_max_count, short step)
+{
+ int free_old = (*max_count) != default_max_count;
+ const knot_rrset_t **old = *rrsets;
+
+ short new_max_count = *max_count + step;
+ const knot_rrset_t **new_rrsets = (const knot_rrset_t **)malloc(
+ new_max_count * sizeof(knot_rrset_t *));
+ CHECK_ALLOC_LOG(new_rrsets, KNOT_ENOMEM);
+
+ memcpy(new_rrsets, *rrsets, (*max_count) * sizeof(knot_rrset_t *));
+
+ *rrsets = new_rrsets;
+ *max_count = new_max_count;
+
+ if (free_old) {
+ free(old);
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+int knot_response_init(knot_packet_t *response)
+{
+ if (response == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ if (response->max_size < KNOT_WIRE_HEADER_SIZE) {
+ return KNOT_ESPACE;
+ }
+
+ // set the qr bit to 1
+ knot_wire_flags_set_qr(&response->header.flags1);
+
+ uint8_t *pos = response->wireformat;
+ knot_packet_header_to_wire(&response->header, &pos,
+ &response->size);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_response_init_from_query(knot_packet_t *response,
+ knot_packet_t *query)
+{
+
+ if (response == NULL || query == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // copy the header from the query
+ memcpy(&response->header, &query->header, sizeof(knot_header_t));
+// memmove(&response->header, &query->header, sizeof(knot_header_t));
+
+ // copy the Question section (but do not copy the QNAME)
+ memcpy(&response->question, &query->question,
+ sizeof(knot_question_t));
+// memmove(&response->question, &query->question,
+// sizeof(knot_question_t));
+
+ int err = 0;
+ // put the qname into the compression table
+ // TODO: get rid of the numeric constants
+ if ((err = knot_response_store_dname_pos(&response->compression,
+ response->question.qname, 0, 12, 12, 0)) != KNOT_EOK) {
+ return err;
+ }
+
+ // copy the wireformat of Header and Question from the query
+ // TODO: get rid of the numeric constants
+ size_t to_copy = 12 + 4 + knot_dname_size(response->question.qname);
+
+ assert(response->max_size >= to_copy);
+// printf("Resp init from query: Copying from: %p to: %p size: %d\n",
+// response->wireformat, query->wireformat,
+// to_copy);
+// printf("Resp init from query: Question name size: %d Query name size: %d\n",
+// knot_dname_size(response->question.qname),
+// knot_dname_size(query->question.qname));
+ memcpy(response->wireformat, query->wireformat, to_copy);
+ response->size = to_copy;
+
+ // set the qr bit to 1
+ knot_wire_flags_set_qr(&response->header.flags1);
+ knot_wire_set_qr(response->wireformat);
+
+ // clear AD flag
+ knot_wire_flags_clear_ad(&response->header.flags2);
+ knot_wire_clear_ad(response->wireformat);
+
+ // clear RA flag
+ knot_wire_flags_clear_ra(&response->header.flags2);
+ knot_wire_clear_ad(response->wireformat);
+
+ // set counts to 0
+ response->header.ancount = 0;
+ response->header.nscount = 0;
+ response->header.arcount = 0;
+
+ response->query = query;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_response_clear(knot_packet_t *resp, int clear_question)
+{
+ if (resp == NULL) {
+ return;
+ }
+
+ resp->size = (clear_question) ? KNOT_WIRE_HEADER_SIZE
+ : KNOT_WIRE_HEADER_SIZE + 4
+ + knot_dname_size(resp->question.qname);
+ resp->an_rrsets = 0;
+ resp->ns_rrsets = 0;
+ resp->ar_rrsets = 0;
+ resp->compression.count = 0;
+ knot_packet_free_tmp_rrsets(resp);
+ resp->tmp_rrsets_count = 0;
+ resp->header.ancount = 0;
+ resp->header.nscount = 0;
+ resp->header.arcount = 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_response_add_opt(knot_packet_t *resp,
+ const knot_opt_rr_t *opt_rr,
+ int override_max_size)
+{
+ if (resp == NULL || opt_rr == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // copy the OPT RR
+ resp->opt_rr.version = opt_rr->version;
+ resp->opt_rr.ext_rcode = opt_rr->ext_rcode;
+ resp->opt_rr.payload = opt_rr->payload;
+ resp->opt_rr.size = opt_rr->size;
+
+ // if max size is set, it means there is some reason to be that way,
+ // so we can't just set it to higher value
+
+ if (override_max_size && resp->max_size > 0
+ && resp->max_size < opt_rr->payload) {
+ return KNOT_EPAYLOAD;
+ }
+
+ // set max size (less is OK)
+ if (override_max_size) {
+ dbg_response("Overriding max size to: %u\n",
+ resp->opt_rr.payload);
+ return knot_packet_set_max_size(resp, resp->opt_rr.payload);
+ //resp->max_size = resp->opt_rr.payload;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_response_add_rrset_answer(knot_packet_t *response,
+ const knot_rrset_t *rrset, int tc,
+ int check_duplicates, int compr_cs)
+{
+ if (response == NULL || rrset == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ dbg_response("add_rrset_answer()\n");
+ assert(response->header.arcount == 0);
+ assert(response->header.nscount == 0);
+
+ if (response->an_rrsets == response->max_an_rrsets
+ && knot_response_realloc_rrsets(&response->answer,
+ &response->max_an_rrsets, DEFAULT_ANCOUNT, STEP_ANCOUNT)
+ != KNOT_EOK) {
+ return KNOT_ENOMEM;
+ }
+
+ if (check_duplicates && knot_packet_contains(response, rrset,
+ KNOT_RRSET_COMPARE_PTR)) {
+ return KNOT_EOK;
+ }
+
+ dbg_response("Trying to add RRSet to Answer section.\n");
+ dbg_response("RRset: %p\n", rrset);
+ dbg_response("Owner: %p\n", rrset->owner);
+
+ int rrs = knot_response_try_add_rrset(response->answer,
+ &response->an_rrsets, response,
+ response->max_size
+ - response->size
+ - response->opt_rr.size
+ - response->tsig_size,
+ rrset, tc, compr_cs);
+
+ if (rrs >= 0) {
+ response->header.ancount += rrs;
+ return KNOT_EOK;
+ }
+
+ return KNOT_ESPACE;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_response_add_rrset_authority(knot_packet_t *response,
+ const knot_rrset_t *rrset, int tc,
+ int check_duplicates, int compr_cs)
+{
+ if (response == NULL || rrset == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ assert(response->header.arcount == 0);
+
+ if (response->ns_rrsets == response->max_ns_rrsets
+ && knot_response_realloc_rrsets(&response->authority,
+ &response->max_ns_rrsets, DEFAULT_NSCOUNT, STEP_NSCOUNT)
+ != 0) {
+ return KNOT_ENOMEM;
+ }
+
+ if (check_duplicates && knot_packet_contains(response, rrset,
+ KNOT_RRSET_COMPARE_PTR)) {
+ return KNOT_EOK;
+ }
+
+ dbg_response("Trying to add RRSet to Authority section.\n");
+
+ int rrs = knot_response_try_add_rrset(response->authority,
+ &response->ns_rrsets, response,
+ response->max_size
+ - response->size
+ - response->opt_rr.size
+ - response->tsig_size,
+ rrset, tc, compr_cs);
+
+ if (rrs >= 0) {
+ response->header.nscount += rrs;
+ return KNOT_EOK;
+ }
+
+ return KNOT_ESPACE;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_response_add_rrset_additional(knot_packet_t *response,
+ const knot_rrset_t *rrset, int tc,
+ int check_duplicates, int compr_cs)
+{
+ if (response == NULL || rrset == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ int ret;
+
+ // if this is the first additional RRSet, add EDNS OPT RR first
+ if (response->header.arcount == 0
+ && response->opt_rr.version != EDNS_NOT_SUPPORTED
+ && (ret = knot_packet_edns_to_wire(response)) != KNOT_EOK) {
+ return ret;
+ }
+
+ if (response->ar_rrsets == response->max_ar_rrsets
+ && knot_response_realloc_rrsets(&response->additional,
+ &response->max_ar_rrsets, DEFAULT_ARCOUNT, STEP_ARCOUNT)
+ != 0) {
+ return KNOT_ENOMEM;
+ }
+
+ if (check_duplicates && knot_packet_contains(response, rrset,
+ KNOT_RRSET_COMPARE_PTR)) {
+ return KNOT_EOK;
+ }
+
+ dbg_response("Trying to add RRSet to Additional section.\n");
+
+ int rrs = knot_response_try_add_rrset(response->additional,
+ &response->ar_rrsets, response,
+ response->max_size
+ - response->size
+ - response->tsig_size, rrset,
+ tc, compr_cs);
+
+ if (rrs >= 0) {
+ response->header.arcount += rrs;
+ return KNOT_EOK;
+ }
+
+ return KNOT_ESPACE;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_response_set_rcode(knot_packet_t *response, short rcode)
+{
+ if (response == NULL) {
+ return;
+ }
+
+ knot_wire_flags_set_rcode(&response->header.flags2, rcode);
+ knot_wire_set_rcode(response->wireformat, rcode);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_response_set_aa(knot_packet_t *response)
+{
+ if (response == NULL) {
+ return;
+ }
+
+ knot_wire_flags_set_aa(&response->header.flags1);
+ knot_wire_set_aa(response->wireformat);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_response_set_tc(knot_packet_t *response)
+{
+ if (response == NULL) {
+ return;
+ }
+
+ knot_wire_flags_set_tc(&response->header.flags1);
+ knot_wire_set_tc(response->wireformat);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_response_add_nsid(knot_packet_t *response, const uint8_t *data,
+ uint16_t length)
+{
+ if (response == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return knot_edns_add_option(&response->opt_rr,
+ EDNS_OPTION_NSID, length, data);
+}
diff --git a/src/libknot/packet/response.h b/src/libknot/packet/response.h
new file mode 100644
index 0000000..38bd9a8
--- /dev/null
+++ b/src/libknot/packet/response.h
@@ -0,0 +1,198 @@
+/*!
+ * \file response.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief API for response manipulation.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_response_H_
+#define _KNOT_response_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "packet/packet.h"
+
+#include "dname.h"
+#include "rrset.h"
+#include "edns.h"
+
+/*!
+ * \brief Default maximum DNS response size
+ *
+ * This size must be supported by all servers and clients.
+ */
+static const short KNOT_MAX_RESPONSE_SIZE = 512;
+
+/*----------------------------------------------------------------------------*/
+int knot_response_init(knot_packet_t *response);
+
+/*!
+ * \brief Initializes response from the given query.
+ *
+ * Copies the header, Changes QR bit to 1, copies the Question section and
+ * stores pointer to the query packet structure in the response packet
+ * structure.
+ *
+ * \warning Never free the query packet structure after calling this function,
+ * it will be freed when the response structure is freed.
+ *
+ * \param response Packet structure representing the response.
+ * \param query Packet structure representing the query.
+ *
+ * \retval KNOT_EOK
+ */
+int knot_response_init_from_query(knot_packet_t *response,
+ knot_packet_t *query);
+
+/*!
+ * \brief Clears the response structure for reuse.
+ *
+ * After call to this function, the response will be in the same state as if
+ * knot_response_new() was called. The maximum wire size is retained.
+ *
+ * \param response Response structure to clear.
+ *
+ * \todo Replace the use of this function with something else maybe?
+ */
+void knot_response_clear(knot_packet_t *resp, int clear_question);
+
+/*!
+ * \brief Sets the OPT RR of the response.
+ *
+ * This function also allocates space for the wireformat of the response, if
+ * the payload in the OPT RR is larger than the current maximum size of the
+ * response and copies the current wireformat over to the new space.
+ *
+ * \note The contents of the OPT RR are copied.
+ *
+ * \param resp Response to set the OPT RR to.
+ * \param opt_rr OPT RR to set.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ *
+ * \todo Needs test.
+ */
+int knot_response_add_opt(knot_packet_t *resp,
+ const knot_opt_rr_t *opt_rr,
+ int override_max_size);
+
+/*!
+ * \brief Adds a RRSet to the Answer section of the response.
+ *
+ * \param response Response to add the RRSet into.
+ * \param rrset RRSet to be added.
+ * \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set.
+ * Otherwise set to 0.
+ * \param check_duplicates Set to <> 0 if the RRSet should not be added to the
+ * response in case it is already there.
+ * \param compr_cs Set to <> 0 if dname compression should use case sensitive
+ * comparation. Set to 0 otherwise.
+ *
+ * \retval KNOT_EOK if successful, or the RRSet was already in the answer.
+ * \retval KNOT_ENOMEM
+ * \retval KNOT_ESPACE
+ */
+int knot_response_add_rrset_answer(knot_packet_t *response,
+ const knot_rrset_t *rrset, int tc,
+ int check_duplicates, int compr_cs);
+
+/*!
+ * \brief Adds a RRSet to the Authority section of the response.
+ *
+ * \param response Response to add the RRSet into.
+ * \param rrset RRSet to be added.
+ * \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set.
+ * Otherwise set to 0.
+ * \param check_duplicates Set to <> 0 if the RRSet should not be added to the
+ * response in case it is already there.
+ * \param compr_cs Set to <> 0 if dname compression should use case sensitive
+ * comparation. Set to 0 otherwise.
+ *
+ * \retval KNOT_EOK if successful, or the RRSet was already in the answer.
+ * \retval KNOT_ENOMEM
+ * \retval KNOT_ESPACE
+ */
+int knot_response_add_rrset_authority(knot_packet_t *response,
+ const knot_rrset_t *rrset, int tc,
+ int check_duplicates, int compr_cs);
+
+/*!
+ * \brief Adds a RRSet to the Additional section of the response.
+ *
+ * \param response Response to add the RRSet into.
+ * \param rrset RRSet to be added.
+ * \param tc Set to <> 0 if omitting this RRSet should result in the TC bit set.
+ * Otherwise set to 0.
+ * \param check_duplicates Set to <> 0 if the RRSet should not be added to the
+ * response in case it is already there.
+ * \param compr_cs Set to <> 0 if dname compression should use case sensitive
+ * comparation. Set to 0 otherwise.
+ *
+ * \retval KNOT_EOK if successful, or the RRSet was already in the answer.
+ * \retval KNOT_ENOMEM
+ * \retval KNOT_ESPACE
+ */
+int knot_response_add_rrset_additional(knot_packet_t *response,
+ const knot_rrset_t *rrset, int tc,
+ int check_duplicates, int compr_cs);
+
+/*!
+ * \brief Sets the RCODE of the response.
+ *
+ * \param response Response to set the RCODE in.
+ * \param rcode RCODE to set.
+ */
+void knot_response_set_rcode(knot_packet_t *response, short rcode);
+
+/*!
+ * \brief Sets the AA bit of the response to 1.
+ *
+ * \param response Response in which the AA bit should be set.
+ */
+void knot_response_set_aa(knot_packet_t *response);
+
+/*!
+ * \brief Sets the TC bit of the response to 1.
+ *
+ * \param response Response in which the TC bit should be set.
+ */
+void knot_response_set_tc(knot_packet_t *response);
+
+/*!
+ * \brief Adds NSID option to the response.
+ *
+ * \param response Response to add the NSID option into.
+ * \param data NSID data.
+ * \param length Size of NSID data in bytes.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+int knot_response_add_nsid(knot_packet_t *response, const uint8_t *data,
+ uint16_t length);
+
+#endif /* _KNOT_response_H_ */
+
+/*! @} */
diff --git a/src/libknot/rdata.c b/src/libknot/rdata.c
new file mode 100644
index 0000000..0c51f5b
--- /dev/null
+++ b/src/libknot/rdata.c
@@ -0,0 +1,838 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "common.h"
+#include "rdata.h"
+#include "util/descriptor.h"
+#include "dname.h"
+#include "util/error.h"
+#include "zone/node.h"
+#include "util/utils.h"
+#include "util/debug.h"
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Compares two RDATA items as binary data.
+ *
+ * \param d1 First item.
+ * \param d2 Second item.
+ * \param count1 Size of the first item in bytes. If set to < 0, the size will
+ * be taken from the first two bytes of \a d1.
+ * \param count2 Size of the second item in bytes. If set to < 0, the size will
+ * be taken from the first two bytes of \a d2.
+ *
+ * \retval 0 if the items are identical.
+ * \retval < 0 if \a d1 goes before \a d2 in canonical order.
+ * \retval > 0 if \a d1 goes after \a d2 in canonical order.
+ */
+static int knot_rdata_compare_binary(const uint8_t *d1, const uint8_t *d2,
+ int count1, int count2)
+{
+ int i1 = 0, i2 = 0;
+
+ // length stored in the first octet
+ if (count1 < 0) {
+ // take count from the first two bytes
+ count1 = (int)(*(uint16_t *)d1);
+ // and start from the third byte
+ i1 = 2;
+ }
+ if (count2 < 0) { // dtto
+ count2 = (int)(*(uint16_t *)d2);
+ i2 = 2;
+ }
+
+
+ while (i1 < count1 && i2 < count2 && d1[i1] == d2[i2]) {
+ ++i1;
+ ++i2;
+ }
+
+ if (i1 == count1 && i2 == count2) {
+ return 0;
+ }
+
+ if (i1 == count1 && i2 < count2) {
+ return -1;
+ } else if (i2 == count2 && i1 < count1) {
+ return 1;
+ } else {
+ assert(i1 < count1 && i2 < count2);
+ return (d1[i1] < d2[i2]) ? -1 : 1;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Retrieves the domain name from MX RDATA.
+ *
+ * \note This is only convenience function. It does not (and cannot) check if
+ * the given RDATA is of the right type, so it always returns the second
+ * RDATA item, even if it is not a domain name.
+ *
+ * \param rdata RDATA to get the MX domain name from.
+ *
+ * \return MX domain name stored in \a rdata or NULL if \a rdata has less than 2
+ * items.
+ */
+static const knot_dname_t *knot_rdata_mx_name(const knot_rdata_t *rdata)
+{
+ if (rdata->count < 2) {
+ return NULL;
+ }
+ return rdata->items[1].dname;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Retrieves the domain name from NS RDATA.
+ *
+ * \note This is only convenience function. It does not (and cannot) check if
+ * the given RDATA is of the right type, so it always returns the first
+ * RDATA item, even if it is not a domain name.
+ *
+ * \param rdata RDATA to get the NS domain name from.
+ *
+ * \return NS domain name stored in \a rdata or NULL if \a rdata has no items.
+ */
+static const knot_dname_t *knot_rdata_ns_name(const knot_rdata_t *rdata)
+{
+ if (rdata->count < 1) {
+ return NULL;
+ }
+ return rdata->items[0].dname;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Retrieves the domain name from SRV RDATA.
+ *
+ * \note This is only convenience function. It does not (and cannot) check if
+ * the given RDATA is of the right type, so it always returns the fourth
+ * RDATA item, even if it is not a domain name.
+ *
+ * \param rdata RDATA to get the SRV domain name from.
+ *
+ * \return SRV domain name stored in \a rdata or NULL if \a rdata has less than
+ * 4 items.
+ */
+static const knot_dname_t *knot_rdata_srv_name(const knot_rdata_t *rdata)
+{
+ if (rdata->count < 4) {
+ return NULL;
+ }
+ return rdata->items[3].dname;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+knot_rdata_t *knot_rdata_new()
+{
+ knot_rdata_t *rdata =
+ (knot_rdata_t *)malloc(sizeof(knot_rdata_t));
+ if (rdata == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ rdata->items = NULL;
+ rdata->count = 0;
+ rdata->next = NULL;
+
+ return rdata;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire,
+ size_t *pos, size_t total_size, size_t rdlength,
+ const knot_rrtype_descriptor_t *desc)
+{
+ int i = 0;
+ uint8_t item_type;
+ size_t parsed = 0;
+
+ if (rdlength == 0) {
+ rdata->items = NULL;
+ return KNOT_EOK;
+ }
+
+ knot_rdata_item_t *items = (knot_rdata_item_t *)malloc(
+ desc->length * sizeof(knot_rdata_item_t));
+ CHECK_ALLOC_LOG(items, KNOT_ENOMEM);
+
+ size_t item_size = 0;
+ uint8_t gateway_type = 0; // only to handle IPSECKEY record
+ knot_dname_t *dname = NULL;
+
+ while (i < desc->length && (desc->fixed_items || parsed < rdlength)) {
+
+ item_type = desc->wireformat[i];
+ item_size = 0;
+
+ size_t pos2;
+
+ switch (item_type) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ pos2 = *pos;
+ dname = knot_dname_parse_from_wire(
+ wire, &pos2, total_size, NULL);
+ if (dname == NULL) {
+ free(items);
+ return KNOT_ERROR;
+ }
+ items[i].dname = dname;
+ //*pos += dname->size;
+ parsed += pos2 - *pos;
+ *pos = pos2;
+ dname = 0;
+ break;
+ case KNOT_RDATA_WF_BYTE:
+ if (desc->type == KNOT_RRTYPE_IPSECKEY && i == 1) {
+ gateway_type = *(wire + *pos);
+ }
+ item_size = 1;
+ break;
+ case KNOT_RDATA_WF_SHORT:
+ item_size = 2;
+ break;
+ case KNOT_RDATA_WF_LONG:
+ item_size = 4;
+ break;
+ case KNOT_RDATA_WF_UINT48:
+ item_size = 6;
+ break;
+ case KNOT_RDATA_WF_TEXT:
+ item_size = rdlength - parsed;
+ break;
+ case KNOT_RDATA_WF_TEXT_SINGLE:
+ item_size = *(wire + *pos) + 1;
+ break;
+ case KNOT_RDATA_WF_A:
+ item_size = 4;
+ break;
+ case KNOT_RDATA_WF_AAAA:
+ item_size = 16;
+ break;
+ case KNOT_RDATA_WF_BINARY:
+ item_size = rdlength - parsed;
+ break;
+ case KNOT_RDATA_WF_BINARYWITHLENGTH:
+ item_size = *(wire + *pos) + 1;
+ break;
+ case KNOT_RDATA_WF_BINARYWITHSHORT:
+ item_size = knot_wire_read_u16(wire + *pos) + 2;
+ break;
+ case KNOT_RDATA_WF_APL:
+ // WTF? what to do with this??
+ // Same as TXT, I guess.
+ item_size = rdlength - parsed;
+ break;
+ case KNOT_RDATA_WF_IPSECGATEWAY:
+ // determine size based on the 'gateway type' field
+ switch (gateway_type) {
+ case 0:
+ item_size = 0;
+ break;
+ case 1:
+ item_size = 4;
+ break;
+ case 2:
+ item_size = 16;
+ break;
+ case 3:
+ pos2 = *pos;
+ fprintf(stderr, "reading dname from pos: %zu\n", pos2);
+ dname =
+ knot_dname_parse_from_wire(
+ wire, &pos2, total_size, NULL);
+ if (dname == NULL) {
+ return KNOT_ERROR;
+ }
+ items[i].dname = dname;
+ //*pos += dname->size;
+ parsed += pos2 - *pos;
+
+ fprintf(stderr, "read %zu bytes.\n", parsed);
+ *pos = pos2;
+ dname = 0;
+ break;
+ default:
+ assert(0);
+ }
+
+ break;
+ default:
+ return KNOT_EMALF;
+
+ }
+
+ if (item_size != 0) {
+ if (parsed + item_size > rdlength) {
+ free(items);
+ return KNOT_EFEWDATA;
+ }
+
+ items[i].raw_data = (uint16_t *)malloc(item_size + 2);
+ if (items[i].raw_data == NULL) {
+ free(items);
+ return KNOT_ENOMEM;
+ }
+ memcpy(items[i].raw_data, &item_size, 2);
+ memcpy(items[i].raw_data + 1, wire + *pos, item_size);
+ *pos += item_size;
+ parsed += item_size;
+ } else if (item_type == KNOT_RDATA_WF_BINARY
+ || item_type == KNOT_RDATA_WF_IPSECGATEWAY) {
+ fprintf(stderr, "item_size was 0, creating empty rdata item.\n");
+ // in this case we are at the end of the RDATA
+ // and should create an empty RDATA item
+ items[i].raw_data = (uint16_t *)malloc(2);
+ if (items[i].raw_data == NULL) {
+ free(items);
+ return KNOT_ENOMEM;
+ }
+ memcpy(items[i].raw_data, &item_size, 2);
+ } else if (item_type != KNOT_RDATA_WF_COMPRESSED_DNAME
+ && item_type != KNOT_RDATA_WF_UNCOMPRESSED_DNAME
+ && item_type != KNOT_RDATA_WF_LITERAL_DNAME) {
+ fprintf(stderr, "RDATA item not set (i: %d), type: %u"
+ " RDATA item type: %d\n", i, desc->type ,item_type);
+ assert(0);
+ }
+
+ ++i;
+ }
+
+ assert(!desc->fixed_items || i == desc->length);
+
+ // all items are parsed, insert into the RDATA
+ int rc;
+ rc = knot_rdata_set_items(rdata, items, i);
+
+ for (int j = 0; j < i; ++j) {
+ assert(rdata->items[j].raw_data != NULL);
+ }
+
+ free(items);
+ return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rdata_set_item(knot_rdata_t *rdata, uint pos,
+ knot_rdata_item_t item)
+{
+ if (pos >= rdata->count) {
+ return KNOT_EBADARG;
+ }
+
+ /*! \todo As in set_items() we should increment refcounter for dnames,
+ * but we don't know the item type.
+ */
+
+ rdata->items[pos] = item; // this should copy the union; or use memcpy?
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+unsigned int knot_rdata_item_count(const knot_rdata_t *rdata)
+{
+ return rdata->count;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rdata_set_items(knot_rdata_t *rdata,
+ const knot_rdata_item_t *items, uint count)
+{
+ if (rdata == NULL || items == NULL || count == 0 ||
+ rdata->items != NULL) {
+ return KNOT_EBADARG;
+ }
+
+ assert(rdata->count == 0);
+ if ((rdata->items = (knot_rdata_item_t *)malloc(
+ count * sizeof(knot_rdata_item_t))) == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(rdata->items, items, count * sizeof(knot_rdata_item_t));
+ rdata->count = count;
+
+ /*! \todo Cannot determine items type, so the dname
+ * refcounters should be increased in caller.
+ */
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rdata_item_t *knot_rdata_item(const knot_rdata_t *rdata,
+ uint pos)
+{
+ if (pos >= rdata->count) {
+ return NULL;
+ } else {
+ return &rdata->items[pos];
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_rdata_item_t *knot_rdata_get_item(const knot_rdata_t *rdata,
+ uint pos)
+{
+ if (pos >= rdata->count) {
+ return NULL;
+ } else {
+ return &rdata->items[pos];
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rdata_item_set_dname(knot_rdata_t *rdata, uint pos,
+ knot_dname_t *dname)
+{
+ if (pos >= rdata->count) {
+ return KNOT_EBADARG;
+ }
+
+ /* Retain dname. */
+ knot_dname_retain(dname);
+
+ rdata->items[pos].dname = dname;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rdata_item_set_raw_data(knot_rdata_t *rdata, uint pos,
+ uint16_t *raw_data)
+{
+ if (pos >= rdata->count) {
+ return KNOT_EBADARG;
+ }
+
+ rdata->items[pos].raw_data = raw_data;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_rdata_free(knot_rdata_t **rdata)
+{
+ if (rdata == NULL || *rdata == NULL) {
+ return;
+ }
+
+ if ((*rdata)->items) {
+ free((*rdata)->items);
+ }
+ free(*rdata);
+ *rdata = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_rdata_deep_free(knot_rdata_t **rdata, uint type,
+ int free_all_dnames)
+{
+ if (rdata == NULL || *rdata == NULL) {
+ return;
+ }
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ assert(desc != NULL);
+
+ assert((*rdata)->count <= desc->length);
+
+ for (int i = 0; i < (*rdata)->count; i++) {
+ if (&((*rdata)->items[i]) == NULL) {
+ continue;
+ }
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME
+ || desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME
+ || desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) {
+ if (((*rdata)->items[i].dname != NULL)) {
+ /*! \todo This is hack to prevent memory errors,
+ * as the rdata_set_items() cannot determine
+ * items type and so cannot increment
+ * reference count in case of dname type.
+ * Free would then release dnames that
+ * aren't referenced by the rdata.
+ */
+ if (free_all_dnames) {
+ knot_dname_release((*rdata)->items[i].dname);
+ }
+ }
+ } else {
+ free((*rdata)->items[i].raw_data);
+ }
+ }
+
+ if ((*rdata)->items) {
+ free((*rdata)->items);
+ }
+ free(*rdata);
+ *rdata = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+/* CLEANUP */
+//uint knot_rdata_wire_size(const knot_rdata_t *rdata,
+// const uint8_t *format)
+//{
+// uint size = 0;
+
+// for (int i = 0; i < rdata->count; ++i) {
+// switch (format[i]) {
+// case KNOT_RDATA_WF_COMPRESSED_DNAME:
+// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+// case KNOT_RDATA_WF_LITERAL_DNAME:
+// size += knot_dname_size(rdata->items[i].dname);
+// break;
+// case KNOT_RDATA_WF_BYTE:
+// size += 1;
+// break;
+// case KNOT_RDATA_WF_SHORT:
+// size += 2;
+// break;
+// case KNOT_RDATA_WF_LONG:
+// size += 4;
+// break;
+// case KNOT_RDATA_WF_A:
+// size += 4;
+// break;
+// case KNOT_RDATA_WF_AAAA:
+// size += 16;
+// break;
+// case KNOT_RDATA_WF_BINARY:
+// case KNOT_RDATA_WF_APL: // saved as binary
+// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary
+// size += rdata->items[i].raw_data[0];
+// break;
+// case KNOT_RDATA_WF_TEXT:
+// case KNOT_RDATA_WF_BINARYWITHLENGTH:
+// size += rdata->items[i].raw_data[0] + 1;
+// break;
+// default:
+// assert(0);
+// }
+// }
+// return size;
+//}
+
+/*----------------------------------------------------------------------------*/
+
+//int knot_rdata_to_wire(const knot_rdata_t *rdata, const uint8_t *format,
+// uint8_t *buffer, uint buf_size)
+//{
+// uint copied = 0;
+// uint8_t tmp[KNOT_MAX_RDATA_WIRE_SIZE];
+// uint8_t *to = tmp;
+
+// for (int i = 0; i < rdata->count; ++i) {
+// assert(copied < KNOT_MAX_RDATA_WIRE_SIZE);
+
+// const uint8_t *from = (uint8_t *)rdata->items[i].raw_data;
+// uint size = 0;
+
+// switch (format[i]) {
+// case KNOT_RDATA_WF_COMPRESSED_DNAME:
+// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+// case KNOT_RDATA_WF_LITERAL_DNAME:
+// size = knot_dname_size(rdata->items[i].dname);
+// from = knot_dname_name(rdata->items[i].dname);
+
+// break;
+// case KNOT_RDATA_WF_BYTE:
+// size = 1;
+// break;
+// case KNOT_RDATA_WF_SHORT:
+// size = 2;
+// break;
+// case KNOT_RDATA_WF_LONG:
+// size = 4;
+// break;
+// case KNOT_RDATA_WF_A:
+// size = 4;
+// break;
+// case KNOT_RDATA_WF_AAAA:
+// size = 16;
+// break;
+// case KNOT_RDATA_WF_TEXT:
+// case KNOT_RDATA_WF_BINARYWITHLENGTH:
+// // size stored in the first two bytes, but in little
+// // endian and we need only the lower byte from it
+// *to = *from; // lower byte is the first in little endian
+// to += 1;
+// case KNOT_RDATA_WF_BINARY:
+// case KNOT_RDATA_WF_APL: // saved as binary
+// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary
+// // size stored in the first two bytes, those bytes
+// // must not be copied
+// size = rdata->items[i].raw_data[0];
+// from += 2; // skip the first two bytes
+// break;
+// default:
+// assert(0);
+// }
+
+// assert(size != 0);
+// assert(copied + size < KNOT_MAX_RDATA_WIRE_SIZE);
+
+// memcpy(to, from, size);
+// to += size;
+// copied += size;
+// }
+
+// if (copied > buf_size) {
+// dbg_rdata("Not enough place allocated for function "
+// "knot_rdata_to_wire(). Allocated %u, need %u\n",
+// buf_size, copied);
+// return -1;
+// }
+
+// memcpy(buffer, tmp, copied);
+// return 0;
+//}
+
+/*----------------------------------------------------------------------------*/
+
+knot_rdata_t *knot_rdata_deep_copy(const knot_rdata_t *rdata,
+ uint16_t type)
+{
+ knot_rdata_t *copy = knot_rdata_new();
+ CHECK_ALLOC_LOG(copy, NULL);
+
+
+ if ((copy->items = (knot_rdata_item_t *)malloc(
+ rdata->count * sizeof(knot_rdata_item_t))) == NULL) {
+ knot_rdata_free(&copy);
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ copy->count = rdata->count;
+
+ knot_rrtype_descriptor_t *d = knot_rrtype_descriptor_by_type(type);
+
+ assert(copy->count <= d->length);
+
+ // copy all items one by one
+ for (int i = 0; i < copy->count; ++i) {
+ if (d->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME
+ || d->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME
+ || d->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME) {
+ copy->items[i].dname =
+ knot_dname_deep_copy(rdata->items[i].dname);
+ } else {
+ copy->items[i].raw_data = (uint16_t *)malloc(
+ rdata->items[i].raw_data[0] + 2);
+ if (copy->items[i].raw_data == NULL) {
+ knot_rdata_deep_free(&copy, type, 1);
+ return NULL;
+ }
+ memcpy(copy->items[i].raw_data,
+ rdata->items[i].raw_data,
+ rdata->items[i].raw_data[0] + 2);
+ }
+ }
+
+ return copy;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rdata_compare(const knot_rdata_t *r1, const knot_rdata_t *r2,
+ const uint8_t *format)
+{
+ uint count = (r1->count < r2->count) ? r1->count : r2->count;
+
+ int cmp = 0;
+
+ for (int i = 0; i < count; ++i) {
+ /* CLEANUP */
+// const uint8_t *data1, *data2;
+// int size1, size2;
+
+ if (format[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ format[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ format[i] == KNOT_RDATA_WF_LITERAL_DNAME) {
+ cmp = knot_dname_compare(r1->items[i].dname,
+ r2->items[i].dname);
+// data1 = knot_dname_name(r1->items[i].dname);
+// data2 = knot_dname_name(r2->items[i].dname);
+// size1 = knot_dname_size(r2->items[i].dname);
+// size2 = knot_dname_size(r2->items[i].dname);
+ } else {
+ cmp = knot_rdata_compare_binary(
+ (uint8_t *)(r1->items[i].raw_data + 1),
+ (uint8_t *)(r2->items[i].raw_data + 1),
+ r1->items[i].raw_data[0],
+ r1->items[i].raw_data[0]);
+// data1 = (uint8_t *)(r1->items[i].raw_data + 1);
+// data2 = (uint8_t *)(r2->items[i].raw_data + 1);
+// size1 = r1->items[i].raw_data[0];
+// size2 = r1->items[i].raw_data[0];
+ }
+
+// cmp =
+
+ if (cmp != 0) {
+ return cmp;
+ }
+ }
+
+ assert(cmp == 0);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_rdata_cname_name(const knot_rdata_t *rdata)
+{
+ if (rdata->count < 1) {
+ return NULL;
+ }
+ return rdata->items[0].dname;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_rdata_dname_target(const knot_rdata_t *rdata)
+{
+ if (rdata->count < 1) {
+ return NULL;
+ }
+ return rdata->items[0].dname;
+}
+
+/*---------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_rdata_get_name(const knot_rdata_t *rdata,
+ uint16_t type)
+{
+ // iterate over the rdata items or act as if we knew where the name is?
+
+ switch (type) {
+ case KNOT_RRTYPE_NS:
+ return knot_rdata_ns_name(rdata);
+ case KNOT_RRTYPE_MX:
+ return knot_rdata_mx_name(rdata);
+ case KNOT_RRTYPE_SRV:
+ return knot_rdata_srv_name(rdata);
+ case KNOT_RRTYPE_CNAME:
+ return knot_rdata_cname_name(rdata);
+ }
+
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+int64_t knot_rdata_soa_serial(const knot_rdata_t *rdata)
+{
+ if (!rdata) {
+ return -1;
+ }
+
+ if (rdata->count < 3) {
+ return -1;
+ }
+
+ // the number is in network byte order, transform it
+ return knot_wire_read_u32((uint8_t *)(rdata->items[2].raw_data + 1));
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint32_t knot_rdata_soa_refresh(const knot_rdata_t *rdata)
+{
+ if (!rdata) {
+ return 0;
+ }
+
+ if (rdata->count < 4) {
+ return 0; /*! \todo Some other error value. */
+ }
+
+ // the number is in network byte order, transform it
+ return knot_wire_read_u32((uint8_t *)(rdata->items[3].raw_data + 1));
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint32_t knot_rdata_soa_retry(const knot_rdata_t *rdata)
+{
+ if (!rdata) {
+ return 0;
+ }
+
+ if (rdata->count < 5) {
+ return 0; /*! \todo Some other error value. */
+ }
+
+ // the number is in network byte order, transform it
+ return knot_wire_read_u32((uint8_t *)(rdata->items[4].raw_data + 1));
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint32_t knot_rdata_soa_expire(const knot_rdata_t *rdata)
+{
+ if (!rdata) {
+ return -1;
+ }
+
+ if (rdata->count < 6) {
+ return 0; /*! \todo Some other error value. */
+ }
+
+ // the number is in network byte order, transform it
+ return knot_wire_read_u32((uint8_t *)(rdata->items[5].raw_data + 1));
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint16_t knot_rdata_rrsig_type_covered(const knot_rdata_t *rdata)
+{
+ if (rdata->count < 1) {
+ return 0;
+ }
+
+ return knot_wire_read_u16((uint8_t *)(rdata->items[0].raw_data + 1));
+}
diff --git a/src/libknot/rdata.h b/src/libknot/rdata.h
new file mode 100644
index 0000000..5d328c9
--- /dev/null
+++ b/src/libknot/rdata.h
@@ -0,0 +1,339 @@
+/*!
+ * \file rdata.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Structures representing RDATA and its items and API for manipulating
+ * both.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_RDATA_H_
+#define _KNOT_RDATA_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "dname.h"
+#include "util/descriptor.h"
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief RDATA item structure.
+ *
+ * Each RDATA may be logically divided into items, each of possible different
+ * type. This structure distinguishes between general data (\a raw_data)
+ * represented as an array of octets, and domain name (\a dname) as domain names
+ * require special treatment within some RDATA (e.g. compressing in packets).
+ */
+union knot_rdata_item {
+ knot_dname_t *dname; /*!< RDATA item represented as a domain name. */
+
+ /*!
+ * \brief RDATA item represented as raw array of octets.
+ *
+ * The first two bytes hold the length of the item in bytes. The length
+ * is stored in little endian.
+ *
+ * In some cases the stored length is also used in the wire format of
+ * RDATA (e.g. character-data as defined in RFC1035). In such case,
+ * the length should be less than 256, so that it fits into one byte
+ * in the wireformat.
+ *
+ * \todo Store the length in system byte order.
+ */
+ uint16_t *raw_data;
+};
+
+typedef union knot_rdata_item knot_rdata_item_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief RDATA structure.
+ *
+ * Each RDATA may be logically divided into items, each of possible different
+ * type (see knot_rdata_item). This structure stores an array of such items.
+ * It is not dynamic, so any RDATA structure may hold either 0 or one specified
+ * number of items which cannot be changed later. However, the number of items
+ * may be different for each RDATA structure. The number of items should be
+ * given by descriptors for each RR type. Some types may have variable number
+ * of items. In such cases, the last item in the array will be set tu NULL
+ * to distinguish the actual count of items.
+ *
+ * This structure does not hold information about the RDATA items, such as
+ * what type is which item or how long are they. This information should be
+ * stored elsewhere (in descriptors) as it is RR-specific and given for each
+ * RR type.
+ *
+ * \todo Find out whether NULL is appropriate value. If it is a possible
+ * value for some of the items, we must find some other way to deal with
+ * this.
+ * \todo Add some function for freeing particular item? Or a non-const getter?
+ */
+struct knot_rdata {
+ knot_rdata_item_t *items; /*!< RDATA items comprising this RDATA. */
+ unsigned int count; /*! < Count of RDATA items in this RDATA. */
+ struct knot_rdata *next; /*!< Next RDATA item in a linked list. */
+};
+
+typedef struct knot_rdata knot_rdata_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates an empty RDATA structure.
+ *
+ * \return Pointer to the new RDATA structure or NULL if an error occured.
+ */
+knot_rdata_t *knot_rdata_new();
+
+/*!
+ * \brief Parses RDATA from the given data in wire format.
+ *
+ * \param rdata RDATA to fill.
+ * \param wire Wire format of the whole data in which the RDATA are present.
+ * \param pos Position in \a wire where to start parsing.
+ * \param total_size Size of the whole data.
+ * \param rdlength Size of the RDATA to parse in bytes.
+ * \param desc RR type descriptor for the RDATA type.
+ *
+ * \retval KNOT_ENOMEM
+ * \retval KNOT_EFEWDATA
+ * \retval KNOT_EMALF
+ * \retval KNOT_ERROR
+ * \retval KNOT_EOK
+ */
+int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire,
+ size_t *pos, size_t total_size, size_t rdlength,
+ const knot_rrtype_descriptor_t *desc);
+
+/*!
+ * \brief Sets the RDATA item on position \a pos.
+ *
+ * \param rdata RDATA structure in which the item should be set.
+ * \param pos Position of the RDATA item to be set.
+ * \param item RDATA item value to be set.
+ *
+ * \retval KNOT_EOK if successful.
+ * \retval KNOT_EBADARG if \a pos is not a valid position.
+ *
+ * \todo Use the union or a pointer to it as parameter? IMHO there is always
+ * only one pointer that is copied, so it doesn't matter.
+ */
+int knot_rdata_set_item(knot_rdata_t *rdata, unsigned int pos,
+ knot_rdata_item_t item);
+
+/*!
+ * \brief Sets all RDATA items within the given RDATA structure.
+ *
+ * \a rdata must be empty so far (\a rdata->count == 0). The necessary space
+ * is allocated.
+ *
+ * This function copies the array of RDATA items from \a items to \a rdata.
+ *
+ * \param rdata RDATA structure to store the items in.
+ * \param items An array of RDATA items to be stored in this RDATA structure.
+ * \param count Count of RDATA items to be stored.
+ *
+ * \retval 0 if successful.
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ */
+int knot_rdata_set_items(knot_rdata_t *rdata,
+ const knot_rdata_item_t *items,
+ unsigned int count);
+
+unsigned int knot_rdata_item_count(const knot_rdata_t *rdata);
+
+/*!
+ * \brief Returns the RDATA item on position \a pos.
+ *
+ * \note Although returning union would be OK (no overhead), we need to be able
+ * to distinguish errors (in this case by returning NULL).
+ *
+ * \param rdata RDATA structure to get the item from.
+ * \param pos Position of the item to retrieve.
+ *
+ * \return The RDATA item on position \a pos, or NULL if such position does not
+ * exist within the given RDATA structure.
+ */
+knot_rdata_item_t *knot_rdata_get_item(const knot_rdata_t *rdata,
+ unsigned int pos);
+
+/*!
+ * \brief Returns the RDATA item on position \a pos.
+ *
+ * \note Although returning union would be OK (no overhead), we need to be able
+ * to distinguish errors (in this case by returning NULL).
+ * \note This function is identical to knot_rdata_get_item(), only it returns
+ * constant data.
+ *
+ * \param rdata RDATA structure to get the item from.
+ * \param pos Position of the item to retrieve.
+ *
+ * \return The RDATA item on position \a pos, or NULL if such position does not
+ * exist within the given RDATA structure.
+ */
+const knot_rdata_item_t *knot_rdata_item(const knot_rdata_t *rdata,
+ unsigned int pos);
+
+/*!
+ * \brief Sets the given domain name as a value of RDATA item on position
+ * \a pos.
+ *
+ * \param rdata RDATA structure to set the item in.
+ * \param pos Position of the RDATA item to set.
+ * \param dname Domain name to set to the item.
+ *
+ * \retval KNOT_EOK if successful.
+ * \retval KNOT_EBADARG
+ */
+int knot_rdata_item_set_dname(knot_rdata_t *rdata, unsigned int pos,
+ knot_dname_t *dname);
+
+/*!
+ * \brief Sets the given raw data as a value of RDATA item on position \a pos.
+ *
+ * \param rdata RDATA structure to set the item in.
+ * \param pos Position of the RDATA item to set.
+ * \param raw_data Raw data to set to the item.
+ *
+ * \retval KNOT_EOK if successful.
+ * \retval KNOT_EBADARG
+ */
+int knot_rdata_item_set_raw_data(knot_rdata_t *rdata, unsigned int pos,
+ uint16_t *raw_data);
+
+/*!
+ * \brief Copies the given RDATA.
+ *
+ * \param rdata RDATA to copy.
+ * \param type RR type of the RDATA.
+ *
+ * \return Copy of \a rdata.
+ */
+knot_rdata_t *knot_rdata_deep_copy(const knot_rdata_t *rdata,
+ uint16_t type);
+
+/*!
+ * \brief Destroys the RDATA structure without deleting RDATA items.
+ *
+ * Also sets the given pointer to NULL.
+ *
+ * \param rdata RDATA structure to be destroyed.
+ */
+void knot_rdata_free(knot_rdata_t **rdata);
+
+/*!
+ * \brief Destroys the RDATA structure and all its RDATA items.
+ *
+ * RDATA items are deleted according to the given RR Type. In case of domain
+ * name, it is deallocated only if either the free_all_dnames parameter is set
+ * to <> 0 or the name does not contain reference to a node (i.e. it is not an
+ * owner of some node) or if it does contain a reference to a node, but is
+ * not equal to its owner. (If free_all_dnames is set to <> 0, no other
+ * condition is evaluated.)
+ *
+ * Also sets the given pointer to NULL.
+ *
+ * \param rdata RDATA structure to be destroyed.
+ * \param type RR Type of the RDATA.
+ * \param free_all_dnames Set to <> 0 if you want to delete ALL domain names
+ * from the RDATA. Set to 0 otherwise.
+ */
+void knot_rdata_deep_free(knot_rdata_t **rdata, unsigned int type,
+ int free_all_dnames);
+
+/*!
+ * \brief Compares two RDATAs of the same type.
+ *
+ * \note Compares domain names normally (dname_compare()), i.e.
+ * case-insensitive.
+ *
+ * \param r1 First RDATA.
+ * \param r2 Second RDATA.
+ * \param format Descriptor of the RDATA format.
+ *
+ * \retval 0 if RDATAs are equal.
+ * \retval < 0 if \a r1 goes before \a r2 in canonical order.
+ * \retval > 0 if \a r1 goes after \a r2 in canonical order.
+ */
+int knot_rdata_compare(const knot_rdata_t *r1, const knot_rdata_t *r2,
+ const uint8_t *format);
+
+/*!
+ * \brief Retrieves the domain name from CNAME RDATA.
+ *
+ * \note This is only convenience function. It does not (and cannot) check if
+ * the given RDATA is of the right type, so it always returns the first
+ * RDATA item, even if it is not a domain name.
+ *
+ * \param rdata RDATA to get the CNAME domain name from.
+ *
+ * \return Canonical name stored in \a rdata or NULL if \a rdata has no items.
+ */
+const knot_dname_t *knot_rdata_cname_name(const knot_rdata_t *rdata);
+
+/*!
+ * \brief Retrieves the domain name from DNAME RDATA.
+ *
+ * \note This is only convenience function. It does not (and cannot) check if
+ * the given RDATA is of the right type, so it always returns the first
+ * RDATA item, even if it is not a domain name.
+ *
+ * \param rdata RDATA to get the DNAME domain name from.
+ *
+ * \return Target domain name stored in \a rdata or NULL if \a rdata has no
+ * items.
+ */
+const knot_dname_t *knot_rdata_dname_target(const knot_rdata_t *rdata);
+
+/*!
+ * \brief Retrieves the domain name from RDATA of given type.
+ *
+ * Supported types:
+ * - KNOT_RRTYPE_NS
+ * - KNOT_RRTYPE_MX
+ * - KNOT_RRTYPE_SRV
+ * - KNOT_RRTYPE_CNAME
+ *
+ * \note This is only convenience function. It does not (and cannot) check if
+ * the given RDATA is of the right type, so it always returns the RDATA
+ * item according to the given type, even if it is not a domain name.
+ *
+ * \param rdata RDATA to get the domain name from.
+ * \param type RR type of the RDATA.
+ *
+ * \return Domain name stored in \a rdata or NULL if \a rdata has not enough
+ * items.
+ */
+const knot_dname_t *knot_rdata_get_name(const knot_rdata_t *rdata,
+ uint16_t type);
+
+int64_t knot_rdata_soa_serial(const knot_rdata_t *rdata);
+
+uint32_t knot_rdata_soa_refresh(const knot_rdata_t *rdata);
+uint32_t knot_rdata_soa_retry(const knot_rdata_t *rdata);
+uint32_t knot_rdata_soa_expire(const knot_rdata_t *rdata);
+
+uint16_t knot_rdata_rrsig_type_covered(const knot_rdata_t *rdata);
+
+#endif /* _KNOT_RDATA_H */
+
+/*! @} */
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
new file mode 100644
index 0000000..6083f77
--- /dev/null
+++ b/src/libknot/rrset.c
@@ -0,0 +1,719 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "common.h"
+#include "rrset.h"
+#include "util/descriptor.h"
+#include "util/error.h"
+#include "util/utils.h"
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+
+static void knot_rrset_disconnect_rdata(knot_rrset_t *rrset,
+ knot_rdata_t *prev, knot_rdata_t *rdata)
+{
+ if (prev == NULL) {
+ // find the previous RDATA in the series, as its pointer must
+ // be changed
+ prev = rdata->next;
+ while (prev->next != rdata) {
+ prev = prev->next;
+ }
+ }
+
+ assert(prev);
+ assert(prev->next == rdata);
+
+ prev->next = rdata->next;
+
+ if (rrset->rdata == rdata) {
+ if (rdata->next == rdata) {
+ rrset->rdata = NULL;
+ } else {
+ rrset->rdata = rdata->next;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type,
+ uint16_t rclass, uint32_t ttl)
+{
+ knot_rrset_t *ret = malloc(sizeof(knot_rrset_t));
+ if (ret == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ ret->rdata = NULL;
+
+ /* Retain reference to owner. */
+ knot_dname_retain(owner);
+
+ ret->owner = owner;
+ ret->type = type;
+ ret->rclass = rclass;
+ ret->ttl = ttl;
+ ret->rrsigs = NULL;
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata)
+{
+ if (rrset == NULL || rdata == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ if (rrset->rdata == NULL) {
+ rrset->rdata = rdata;
+ rrset->rdata->next = rrset->rdata;
+ } else {
+ knot_rdata_t *tmp;
+
+ tmp = rrset->rdata;
+
+ while (tmp->next != rrset->rdata) {
+ tmp = tmp->next;
+ }
+ rdata->next = tmp->next;
+ tmp->next = rdata;
+ }
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_rdata_t *knot_rrset_remove_rdata(knot_rrset_t *rrset,
+ const knot_rdata_t *rdata)
+{
+ if (rrset == NULL || rdata == NULL) {
+ return NULL;
+ }
+
+ knot_rdata_t *prev = NULL;
+ knot_rdata_t *rr = rrset->rdata;
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+
+ if (desc == NULL) {
+ return NULL;
+ }
+
+ while (rr != NULL) {
+ /*! \todo maybe the dnames should be compared case-insensitive*/
+ if (knot_rdata_compare(rr, rdata, desc->wireformat) == 0) {
+ knot_rrset_disconnect_rdata(rrset, prev, rr);
+ return rr;
+ }
+ prev = rr;
+ rr = knot_rrset_rdata_get_next(rrset, rr);
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_set_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs)
+{
+ if (rrset == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ rrset->rrsigs = rrsigs;
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_add_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs,
+ knot_rrset_dupl_handling_t dupl)
+{
+ if (rrset == NULL || rrsigs == NULL
+ || knot_dname_compare(rrset->owner, rrsigs->owner) != 0) {
+ return KNOT_EBADARG;
+ }
+
+ int rc;
+ if (rrset->rrsigs != NULL) {
+ if (dupl == KNOT_RRSET_DUPL_MERGE) {
+ rc = knot_rrset_merge((void **)&rrset->rrsigs,
+ (void **)&rrsigs);
+ if (rc != KNOT_EOK) {
+ return rc;
+ } else {
+ return 1;
+ }
+ } else if (dupl == KNOT_RRSET_DUPL_SKIP) {
+ return 2;
+ } else if (dupl == KNOT_RRSET_DUPL_REPLACE) {
+ rrset->rrsigs = rrsigs;
+ }
+ } else {
+ rrset->rrsigs = rrsigs;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_rrset_owner(const knot_rrset_t *rrset)
+{
+ return rrset->owner;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_rrset_get_owner(const knot_rrset_t *rrset)
+{
+ return rrset->owner;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_rrset_set_owner(knot_rrset_t *rrset, knot_dname_t* owner)
+{
+ if (rrset) {
+ /* Retain new owner and release old owner. */
+ knot_dname_retain(owner);
+ knot_dname_release(rrset->owner);
+ rrset->owner = owner;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint16_t knot_rrset_type(const knot_rrset_t *rrset)
+{
+ return rrset->type;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint16_t knot_rrset_class(const knot_rrset_t *rrset)
+{
+ return rrset->rclass;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint32_t knot_rrset_ttl(const knot_rrset_t *rrset)
+{
+ return rrset->ttl;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rdata_t *knot_rrset_rdata(const knot_rrset_t *rrset)
+{
+ return rrset->rdata;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rdata_t *knot_rrset_rdata_next(const knot_rrset_t *rrset,
+ const knot_rdata_t *rdata)
+{
+ if (rdata == NULL) {
+ return rrset->rdata;
+ }
+ if (rdata->next == rrset->rdata) {
+ return NULL;
+ } else {
+ return rdata->next;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_rdata_t *knot_rrset_get_rdata(knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return NULL;
+ } else {
+ return rrset->rdata;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_rdata_t *knot_rrset_rdata_get_next(knot_rrset_t *rrset,
+ knot_rdata_t *rdata)
+{
+ if (rdata->next == rrset->rdata) {
+ return NULL;
+ } else {
+ return rdata->next;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_rdata_rr_count(const knot_rrset_t *rrset)
+{
+ int count = 0;
+ const knot_rdata_t *rdata = rrset->rdata;
+
+ while (rdata != NULL) {
+ ++count;
+ rdata = knot_rrset_rdata_next(rrset, rdata);
+ }
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rrset_t *knot_rrset_rrsigs(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ assert(0);
+ return NULL;
+ } else {
+ return rrset->rrsigs;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_rrset_t *knot_rrset_get_rrsigs(knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ assert(0);
+ return NULL;
+ } else {
+ return rrset->rrsigs;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2)
+{
+ if (r1 == NULL || r2 == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(r1->type);
+ if (desc == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // compare RDATA sets (order is not significant)
+ const knot_rdata_t *rdata1= knot_rrset_rdata(r1);
+ const knot_rdata_t *rdata2;
+
+ // find all RDATA from r1 in r2
+ while (rdata1 != NULL) {
+ rdata2 = knot_rrset_rdata(r2);
+ while (rdata2 != NULL && knot_rdata_compare(rdata1, rdata2,
+ desc->wireformat)) {
+ rdata2 = knot_rrset_rdata_next(r2, rdata2);
+ }
+
+ if (rdata2 == NULL) {
+ // RDATA from r1 not found in r2
+ return 0;
+ }
+
+ // otherwise it was found, continue with next r1 RDATA
+ rdata1 = knot_rrset_rdata_next(r1, rdata1);
+ }
+
+ // find all RDATA from r2 in r1 (this can be done in a better way)
+ rdata2 = knot_rrset_rdata(r2);
+ while (rdata2 != NULL) {
+ rdata1 = knot_rrset_rdata(r1);
+ while (rdata2 != NULL && knot_rdata_compare(rdata1, rdata2,
+ desc->wireformat)) {
+ rdata1 = knot_rrset_rdata_next(r1, rdata1);
+ }
+
+ if (rdata1 == NULL) {
+ // RDATA from r1 not found in r2
+ return 0;
+ }
+
+ // otherwise it was found, continue with next r1 RDATA
+ rdata2 = knot_rrset_rdata_next(r2, rdata2);
+ }
+
+ // all RDATA found
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset,
+ const knot_rdata_t *rdata, uint8_t **pos,
+ size_t max_size)
+{
+ int size = 0;
+
+ assert(rrset != NULL);
+ assert(rrset->owner != NULL);
+ assert(rdata != NULL);
+ assert(pos != NULL);
+ assert(*pos != NULL);
+
+ fprintf(stderr, "Max size: %zu, owner: %p, owner size: %d\n",
+ max_size, rrset->owner, rrset->owner->size);
+
+ // check if owner fits
+ if (size + knot_dname_size(rrset->owner) + 10 > max_size) {
+ return KNOT_ESPACE;
+ }
+
+ memcpy(*pos, knot_dname_name(rrset->owner),
+ knot_dname_size(rrset->owner));
+ *pos += knot_dname_size(rrset->owner);
+ size += knot_dname_size(rrset->owner);
+
+ fprintf(stderr, "Max size: %zu, size: %d\n", max_size, size);
+
+ fprintf(stderr, "Wire format:\n");
+
+ // put rest of RR 'header'
+ knot_wire_write_u16(*pos, rrset->type);
+ fprintf(stderr, " Type: %u\n", rrset->type);
+ *pos += 2;
+
+ knot_wire_write_u16(*pos, rrset->rclass);
+ fprintf(stderr, " Class: %u\n", rrset->rclass);
+ *pos += 2;
+
+ knot_wire_write_u32(*pos, rrset->ttl);
+ fprintf(stderr, " TTL: %u\n", rrset->ttl);
+ *pos += 4;
+
+ // save space for RDLENGTH
+ uint8_t *rdlength_pos = *pos;
+ *pos += 2;
+
+ size += 10;
+// compr->wire_pos += size;
+
+ fprintf(stderr, "Max size: %zu, size: %d\n", max_size, size);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+
+ uint16_t rdlength = 0;
+
+ for (int i = 0; i < rdata->count; ++i) {
+ if (max_size < size + rdlength) {
+ return KNOT_ESPACE;
+ }
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME: {
+ knot_dname_t *dname =
+ knot_rdata_item(rdata, i)->dname;
+ if (size + rdlength + dname->size > max_size) {
+ return KNOT_ESPACE;
+ }
+
+ // save whole domain name
+ memcpy(*pos, knot_dname_name(dname),
+ knot_dname_size(dname));
+ fprintf(stderr, "Uncompressed dname size: %d\n",
+ knot_dname_size(dname));
+ *pos += knot_dname_size(dname);
+ rdlength += knot_dname_size(dname);
+// compr->wire_pos += dname->size;
+ break;
+ }
+ default: {
+ uint16_t *raw_data =
+ knot_rdata_item(rdata, i)->raw_data;
+
+ if (size + rdlength + raw_data[0] > max_size) {
+ return KNOT_ESPACE;
+ }
+
+ // copy just the rdata item data (without size)
+ memcpy(*pos, raw_data + 1, raw_data[0]);
+ fprintf(stderr, "Raw data size: %d\n", raw_data[0]);
+ *pos += raw_data[0];
+ rdlength += raw_data[0];
+// compr->wire_pos += raw_data[0];
+ break;
+ }
+ }
+ }
+
+ fprintf(stderr, "Max size: %zu, size: %d\n", max_size, size);
+
+ assert(size + rdlength <= max_size);
+ size += rdlength;
+ knot_wire_write_u16(rdlength_pos, rdlength);
+
+ return size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size,
+ int *rr_count)
+{
+ // if no RDATA in RRSet, return
+ if (rrset->rdata == NULL) {
+ *size = 0;
+ *rr_count = 0;
+ return KNOT_EOK;
+ }
+
+
+ uint8_t *pos = wire;
+ int rrs = 0;
+ short rrset_size = 0;
+
+ const knot_rdata_t *rdata = rrset->rdata;
+ do {
+ int ret = knot_rrset_rr_to_wire(rrset, rdata, &pos,
+ *size - rrset_size);
+
+ assert(ret != 0);
+
+ if (ret < 0) {
+ // some RR didn't fit in, so no RRs should be used
+ // TODO: remove last entries from compression table
+ fprintf(stderr, "Some RR didn't fit in.\n");
+ return KNOT_ESPACE;
+ }
+
+ fprintf(stderr, "RR of size %d added.\n", ret);
+ rrset_size += ret;
+ ++rrs;
+ } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL);
+
+ // the whole RRSet did fit in
+ assert(rrset_size <= *size);
+ assert(pos - wire == rrset_size);
+ *size = rrset_size;
+
+ fprintf(stderr, " Size after: %zu\n", *size);
+
+ *rr_count = rrs;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_compare(const knot_rrset_t *r1,
+ const knot_rrset_t *r2,
+ knot_rrset_compare_type_t cmp)
+{
+ if (cmp == KNOT_RRSET_COMPARE_PTR) {
+ return (r1 == r2);
+ }
+
+ int res = ((r1->rclass == r2->rclass)
+ && (r1->type == r2->type)
+ && (r1->ttl == r2->ttl)
+ && knot_dname_compare(r1->owner, r2->owner) == 0);
+
+ if (cmp == KNOT_RRSET_COMPARE_WHOLE && res) {
+ res = knot_rrset_compare_rdata(r1, r2);
+ if (res < 0) {
+ return 0;
+ }
+ }
+
+ return res;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to)
+{
+ if (from == NULL || to == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ int ret;
+
+ *to = (knot_rrset_t *)calloc(1, sizeof(knot_rrset_t));
+ CHECK_ALLOC_LOG(*to, KNOT_ENOMEM);
+
+ (*to)->owner = knot_dname_deep_copy(from->owner);
+ (*to)->rclass = from->rclass;
+ (*to)->ttl = from->ttl;
+ (*to)->type = from->type;
+ if (from->rrsigs != NULL) {
+ ret = knot_rrset_deep_copy(from->rrsigs, &(*to)->rrsigs);
+ if (ret != KNOT_EOK) {
+ knot_rrset_deep_free(to, 1, 0, 0);
+ return ret;
+ }
+ }
+ assert((*to)->rrsigs == NULL || from->rrsigs != NULL);
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(from);
+
+ /*! \note Order of RDATA will be reversed. */
+ while (rdata != NULL) {
+ ret = knot_rrset_add_rdata(*to, knot_rdata_deep_copy(rdata,
+ knot_rrset_type(from)));
+ if (ret != KNOT_EOK) {
+ knot_rrset_deep_free(to, 1, 1, 1);
+ return ret;
+ }
+ rdata = knot_rrset_rdata_next(from, rdata);
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to)
+{
+ *to = (knot_rrset_t *)malloc(sizeof(knot_rrset_t));
+ CHECK_ALLOC_LOG(*to, KNOT_ENOMEM);
+
+ memcpy(*to, from, sizeof(knot_rrset_t));
+
+ /* Retain owner. */
+ knot_dname_retain((*to)->owner);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_rrset_free(knot_rrset_t **rrset)
+{
+ if (rrset == NULL || *rrset == NULL) {
+ return;
+ }
+
+ /*! \todo Shouldn't we always release owner reference? */
+ knot_dname_release((*rrset)->owner);
+
+ free(*rrset);
+ *rrset = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner,
+ int free_rdata, int free_rdata_dnames)
+{
+ if (rrset == NULL || *rrset == NULL) {
+ return;
+ }
+
+ if (free_rdata) {
+ knot_rdata_t *tmp_rdata;
+ knot_rdata_t *next_rdata;
+ tmp_rdata = (*rrset)->rdata;
+
+ while ((tmp_rdata != NULL)
+ && (tmp_rdata->next != (*rrset)->rdata)
+ && (tmp_rdata->next != NULL)) {
+ next_rdata = tmp_rdata->next;
+ knot_rdata_deep_free(&tmp_rdata, (*rrset)->type,
+ free_rdata_dnames);
+ tmp_rdata = next_rdata;
+ }
+
+ assert(tmp_rdata == NULL
+ || tmp_rdata->next == (*rrset)->rdata);
+
+ knot_rdata_deep_free(&tmp_rdata, (*rrset)->type,
+ free_rdata_dnames);
+ }
+
+ // RRSIGs should have the same owner as this RRSet, so do not delete it
+ if ((*rrset)->rrsigs != NULL) {
+ knot_rrset_deep_free(&(*rrset)->rrsigs, 0, 1,
+ free_rdata_dnames);
+ }
+
+ /*! \todo Release owner every time? */
+ //if (free_owner) {
+ knot_dname_release((*rrset)->owner);
+ //}
+
+ free(*rrset);
+ *rrset = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_rrset_merge(void **r1, void **r2)
+{
+ knot_rrset_t *rrset1 = (knot_rrset_t *)(*r1);
+ knot_rrset_t *rrset2 = (knot_rrset_t *)(*r2);
+
+ if ((knot_dname_compare(rrset1->owner, rrset2->owner) != 0)
+ || rrset1->rclass != rrset2->rclass
+ || rrset1->type != rrset2->type
+ || rrset1->ttl != rrset2->ttl) {
+ return KNOT_EBADARG;
+ }
+
+ // add all RDATAs from rrset2 to rrset1 (i.e. concatenate linked lists)
+
+ // no RDATA in RRSet 1
+ assert(rrset1 && rrset2);
+ if (rrset1->rdata == NULL) {
+ rrset1->rdata = rrset2->rdata;
+ return KNOT_EOK;
+ }
+
+ knot_rdata_t *tmp_rdata = rrset1->rdata;
+
+ if (!tmp_rdata) {
+ return KNOT_EOK;
+ }
+
+ while (tmp_rdata->next != rrset1->rdata) {
+ tmp_rdata = tmp_rdata->next;
+ }
+
+ tmp_rdata->next = rrset2->rdata;
+
+ tmp_rdata = rrset2->rdata; //maybe unnecessary, but is clearer
+
+ while (tmp_rdata->next != rrset2->rdata) {
+ tmp_rdata = tmp_rdata->next;
+ }
+
+ tmp_rdata->next = rrset1->rdata;
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h
new file mode 100644
index 0000000..7754c7f
--- /dev/null
+++ b/src/libknot/rrset.h
@@ -0,0 +1,306 @@
+/*!
+ * \file rrset.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief RRSet structure and API for manipulating it.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_RRSET_H_
+#define _KNOT_RRSET_H_
+
+#include <stdint.h>
+
+#include "dname.h"
+#include "rdata.h"
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Structure for representing an RRSet.
+ *
+ * For definition of a RRSet see RFC2181, Section 5.
+ *
+ * As all RRs within a RRSet share the same OWNER, TYPE, CLASS and TTL (see
+ * Section 5.2 of RFC2181), there is no need to duplicate these data in the
+ * program. Distinct Resource Records are thus represented only as distinct
+ * RDATA sections of corresponding RRs.
+ */
+struct knot_rrset {
+ /*! \brief Domain name being the owner of the RRSet. */
+ knot_dname_t *owner;
+ uint16_t type; /*!< TYPE of the RRset. */
+ uint16_t rclass; /*!< CLASS of the RRSet. */
+ uint32_t ttl; /*!< TTL of the RRSet. */
+ /*!
+ * \brief First item in an ordered cyclic list of RDATA items.
+ *
+ * \note The fact that the list is cyclic will easily allow for
+ * possible round-robin rotation of RRSets.
+ */
+ knot_rdata_t *rdata;
+ struct knot_rrset *rrsigs; /*!< Set of RRSIGs covering this RRSet. */
+};
+
+typedef struct knot_rrset knot_rrset_t;
+
+/*----------------------------------------------------------------------------*/
+
+typedef enum {
+ KNOT_RRSET_COMPARE_PTR,
+ KNOT_RRSET_COMPARE_HEADER,
+ KNOT_RRSET_COMPARE_WHOLE
+} knot_rrset_compare_type_t;
+
+typedef enum {
+ KNOT_RRSET_DUPL_MERGE,
+ KNOT_RRSET_DUPL_REPLACE,
+ KNOT_RRSET_DUPL_SKIP
+} knot_rrset_dupl_handling_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates a new RRSet with the given properties.
+ *
+ * The created RRSet contains no RDATAs (i.e. is actually empty).
+ *
+ * \param owner OWNER of the RRSet.
+ * \param type TYPE of the RRSet.
+ * \param rclass CLASS of the RRSet.
+ * \param ttl TTL of the RRset.
+ *
+ * \return New RRSet structure with the given OWNER, TYPE, CLASS and TTL or NULL
+ * if an error occured.
+ */
+knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type,
+ uint16_t rclass, uint32_t ttl);
+
+/*!
+ * \brief Adds the given RDATA to the RRSet.
+ *
+ * \param rrset RRSet to add the RDATA to.
+ * \param rdata RDATA to add to the RRSet.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ *
+ * \todo Provide some function for comparing RDATAs.
+ */
+int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata);
+
+knot_rdata_t * knot_rrset_remove_rdata(knot_rrset_t *rrset,
+ const knot_rdata_t *rdata);
+
+/*!
+ * \brief Adds RRSIG signatures to this RRSet.
+ *
+ * \param rrset RRSet to add the signatures into.
+ * \param rrsigs Set of RRSIGs covering this RRSet.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ */
+int knot_rrset_set_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs);
+
+int knot_rrset_add_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs,
+ knot_rrset_dupl_handling_t dupl);
+
+/*!
+ * \brief Returns the Owner of the RRSet.
+ *
+ * \param rrset RRSet to get the Owner of.
+ *
+ * \return Owner of the given RRSet.
+ */
+const knot_dname_t *knot_rrset_owner(const knot_rrset_t *rrset);
+
+/*!
+ * \todo Document me.
+ */
+knot_dname_t *knot_rrset_get_owner(const knot_rrset_t *rrset);
+
+/*!
+ * \brief Set rrset owner to specified dname.
+ *
+ * Previous owner will be replaced if exist.
+ *
+ * \param rrset Specified RRSet.
+ * \param owner New owner dname.
+ */
+void knot_rrset_set_owner(knot_rrset_t *rrset, knot_dname_t* owner);
+
+/*!
+ * \brief Returns the TYPE of the RRSet.
+ *
+ * \param rrset RRSet to get the TYPE of.
+ *
+ * \return TYPE of the given RRSet.
+ */
+uint16_t knot_rrset_type(const knot_rrset_t *rrset);
+
+/*!
+ * \brief Returns the CLASS of the RRSet.
+ *
+ * \param rrset RRSet to get the CLASS of.
+ *
+ * \return CLASS of the given RRSet.
+ */
+uint16_t knot_rrset_class(const knot_rrset_t *rrset);
+
+/*!
+ * \brief Returns the TTL of the RRSet.
+ *
+ * \param rrset RRSet to get the TTL of.
+ *
+ * \return TTL of the given RRSet.
+ */
+uint32_t knot_rrset_ttl(const knot_rrset_t *rrset);
+
+/*!
+ * \brief Returns the first RDATA in the RRSet.
+ *
+ * RDATAs in a RRSet are stored in a ordered cyclic list.
+ *
+ * \note If later a round-robin rotation of RRSets is employed, the RDATA
+ * returned by this function may not be the first RDATA in canonical
+ * order.
+ *
+ * \param rrset RRSet to get the RDATA from.
+ *
+ * \return First RDATA in the given RRSet.
+ */
+const knot_rdata_t *knot_rrset_rdata(const knot_rrset_t *rrset);
+
+const knot_rdata_t *knot_rrset_rdata_next(const knot_rrset_t *rrset,
+ const knot_rdata_t *rdata);
+
+/*!
+ * \brief Returns the first RDATA in the RRSet (non-const version).
+ *
+ * RDATAs in a RRSet are stored in a ordered cyclic list.
+ *
+ * \note If later a round-robin rotation of RRSets is employed, the RDATA
+ * returned by this function may not be the first RDATA in canonical
+ * order.
+ *
+ * \param rrset RRSet to get the RDATA from.
+ *
+ * \return First RDATA in the given RRSet or NULL if there is none or if no
+ * rrset was provided (\a rrset is NULL).
+ */
+knot_rdata_t *knot_rrset_get_rdata(knot_rrset_t *rrset);
+
+knot_rdata_t *knot_rrset_rdata_get_next(knot_rrset_t *rrset,
+ knot_rdata_t *rdata);
+
+int knot_rrset_rdata_rr_count(const knot_rrset_t *rrset);
+
+/*!
+ * \brief Returns the set of RRSIGs covering the given RRSet.
+ *
+ * \param rrset RRSet to get the signatures for.
+ *
+ * \return Set of RRSIGs which cover the given RRSet or NULL if there is none or
+ * if no rrset was provided (\a rrset is NULL).
+ */
+const knot_rrset_t *knot_rrset_rrsigs(const knot_rrset_t *rrset);
+
+knot_rrset_t *knot_rrset_get_rrsigs(knot_rrset_t *rrset);
+
+int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2);
+
+int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size,
+ int *rr_count);
+
+/*!
+ * \brief Compares two RRSets.
+ *
+ * \note This function does not return 'standard' compare return values, because
+ * there is no way to define which RRSet is 'larger'.
+ *
+ * \param r1 First RRSet.
+ * \param r2 Second RRSet.
+ * \param cmp Type of comparison to perform.
+ *
+ * \retval <> 0 If RRSets are equal.
+ * \retval 0 if RRSets are not equal.
+ */
+int knot_rrset_compare(const knot_rrset_t *r1,
+ const knot_rrset_t *r2,
+ knot_rrset_compare_type_t cmp);
+
+/*! \todo Add unit test. */
+int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to);
+
+/*! \todo Add unit test. */
+int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to);
+
+/*!
+ * \brief Destroys the RRSet structure.
+ *
+ * Does not destroy the OWNER domain name structure, nor the signatures, as
+ * these may be used elsewhere.
+ *
+ * Does not destroy RDATA structures neither, as they need special processing.
+ *
+ * Also sets the given pointer to NULL.
+ *
+ * \param rrset RRset to be destroyed.
+ */
+void knot_rrset_free(knot_rrset_t **rrset);
+
+/*!
+ * \brief Destroys the RRSet structure and all its substructures.
+ *
+ * Also sets the given pointer to NULL.
+ *
+ * \param rrset RRset to be destroyed.
+ * \param free_owner Set to 0 if you do not want the owner domain name to be
+ * destroyed also. Set to <> 0 otherwise.
+ * \param free_rdata ***\todo DOCUMENT ME***
+ * \param free_rdata_dnames Set to <> 0 if you want to delete ALL domain names
+ * present in RDATA. Set to 0 otherwise. (See
+ * knot_rdata_deep_free().)
+ */
+void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner,
+ int free_rdata, int free_rdata_dnames);
+
+/*!
+ * \brief Merges two RRSets.
+ *
+ * Merges \a r1 into \a r2 by concatenating the list of RDATAs in \a r2 after
+ * the list of RDATAs in \a r1. \a r2 is unaffected by this, though you must not
+ * destroy the RDATAs in \a r2 as they are now also in \a r1. (You may use
+ * function knot_rrset_free() though, as it does not touch RDATAs).
+ *
+ * \note Member \a rrsigs is preserved from the first RRSet.
+ *
+ * \param r1 Pointer to RRSet to be merged into.
+ * \param r2 Poitner to RRSet to be merged.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG if the RRSets could not be merged, because their
+ * Owner, Type, Class or TTL does not match.
+ */
+int knot_rrset_merge(void **r1, void **r2);
+
+#endif /* _KNOT_RRSET_H_ */
+
+/*! @} */
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
new file mode 100644
index 0000000..3178a23
--- /dev/null
+++ b/src/libknot/tsig-op.c
@@ -0,0 +1,1089 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "common.h"
+#include "tsig.h"
+#include "tsig-op.h"
+#include "util/wire.h"
+#include "util/error.h"
+#include "util/debug.h"
+
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+
+static int b64rmap_initialized = 0;
+static uint8_t b64rmap[256];
+
+static const uint8_t b64rmap_special = 0xf0;
+static const uint8_t b64rmap_end = 0xfd;
+static const uint8_t b64rmap_space = 0xfe;
+static const uint8_t b64rmap_invalid = 0xff;
+
+/**
+ * Initializing the reverse map is not thread safe.
+ * Which is fine for NSD. For now...
+ **/
+void b64_initialize_rmap()
+{
+ int i;
+ char ch;
+
+ /* Null: end of string, stop parsing */
+ b64rmap[0] = b64rmap_end;
+
+ for (i = 1; i < 256; ++i) {
+ ch = (char)i;
+ /* Whitespaces */
+ if (isspace(ch)) {
+ b64rmap[i] = b64rmap_space;
+ }
+ /* Padding: stop parsing */
+ else if (ch == Pad64) {
+ b64rmap[i] = b64rmap_end;
+ }
+ /* Non-base64 char */
+ else {
+ b64rmap[i] = b64rmap_invalid;
+ }
+ }
+
+ /* Fill reverse mapping for base64 chars */
+ for (i = 0; Base64[i] != '\0'; ++i) {
+ b64rmap[(uint8_t)Base64[i]] = i;
+ }
+
+ b64rmap_initialized = 1;
+}
+
+int b64_pton_do(char const *src, uint8_t *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ uint8_t ofs;
+
+ state = 0;
+ tarindex = 0;
+
+ while (1) {
+ ch = *src++;
+ ofs = b64rmap[ch];
+
+ if (ofs >= b64rmap_special) {
+ /* Ignore whitespaces */
+ if (ofs == b64rmap_space) {
+ continue;
+ }
+ /* End of base64 characters */
+ if (ofs == b64rmap_end) {
+ break;
+ }
+ /* A non-base64 character. */
+ return (-1);
+ }
+
+ switch (state) {
+ case 0:
+ if ((size_t)tarindex >= targsize) {
+ return (-1);
+ }
+ target[tarindex] = ofs << 2;
+ state = 1;
+ break;
+ case 1:
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs >> 4;
+ target[tarindex+1] = (ofs & 0x0f)
+ << 4 ;
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs >> 2;
+ target[tarindex+1] = (ofs & 0x03)
+ << 6;
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if ((size_t)tarindex >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs;
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ break;
+ }
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64) {
+ return (-1);
+ }
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ return (-1);
+ }
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target[tarindex] != 0) {
+ return (-1);
+ }
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0) {
+ return (-1);
+ }
+ }
+
+ return (tarindex);
+}
+
+
+int b64_pton_len(char const *src)
+{
+ int tarindex, state, ch;
+ uint8_t ofs;
+
+ state = 0;
+ tarindex = 0;
+
+ while (1) {
+ ch = *src++;
+ ofs = b64rmap[ch];
+
+ if (ofs >= b64rmap_special) {
+ /* Ignore whitespaces */
+ if (ofs == b64rmap_space) {
+ continue;
+ }
+ /* End of base64 characters */
+ if (ofs == b64rmap_end) {
+ break;
+ }
+ /* A non-base64 character. */
+ return (-1);
+ }
+
+ switch (state) {
+ case 0:
+ state = 1;
+ break;
+ case 1:
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ break;
+ }
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64) {
+ return (-1);
+ }
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ return (-1);
+ }
+
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0) {
+ return (-1);
+ }
+ }
+
+ return (tarindex);
+}
+
+int b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+ if (!b64rmap_initialized) {
+ b64_initialize_rmap();
+ }
+
+ if (target) {
+ return b64_pton_do(src, target, targsize);
+ } else {
+ return b64_pton_len(src);
+ }
+}
+
+#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */
+
+
+
+
+
+
+
+
+
+
+
+
+const int KNOT_TSIG_MAX_DIGEST_SIZE = 64; // size of HMAC-SHA512 digest
+
+
+static int knot_tsig_check_algorithm(const knot_rrset_t *tsig_rr)
+{
+ const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr);
+ if (!alg_name) {
+ return KNOT_EMALF;
+ }
+
+ tsig_algorithm_t alg = tsig_alg_from_name(alg_name);
+ if (alg == 0) {
+ /*!< \todo is this error OK? */
+ dbg_tsig("TSIG: unknown algorithm.\n");
+ return KNOT_TSIG_EBADSIG;
+ }
+
+ return KNOT_EOK;
+}
+
+static int knot_tsig_check_key(const knot_rrset_t *tsig_rr,
+ const knot_key_t *tsig_key)
+{
+ const knot_dname_t *tsig_name = knot_rrset_owner(tsig_rr);
+ if (!tsig_name) {
+ return KNOT_EMALF;
+ }
+
+ const char *name = knot_dname_to_str(tsig_name);
+ if (!name) {
+ return KNOT_EMALF;
+ }
+
+ if (knot_dname_compare(tsig_name, tsig_key->name) != 0) {
+ /*!< \todo which error. */
+ dbg_tsig("TSIG: unknown key: %s\n", name);
+ return KNOT_TSIG_EBADKEY;
+ }
+
+ return KNOT_EOK;
+}
+
+static int knot_tsig_compute_digest(const uint8_t *wire, size_t wire_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_key_t *key)
+{
+ if (!wire || !digest || !digest_len || !key) {
+ dbg_tsig("TSIG: digest: bad args.\n");
+ return KNOT_EBADARG;
+ }
+
+ if (!key->name) {
+ dbg_tsig("TSIG: digest: no algorithm\n");
+ return KNOT_EMALF;
+ }
+
+ tsig_algorithm_t tsig_alg = key->algorithm;
+ if (tsig_alg == 0) {
+ dbg_tsig("TSIG: digest: unknown algorithm\n");
+ return KNOT_TSIG_EBADSIG;
+ }
+
+ /* Create digest, using length of the algorithm. */
+// *digest = malloc(sizeof(uint8_t) * tsig_alg_digest_length(tsig_alg));
+// if (!digest) {
+// ERR_ALLOC_FAILED;
+// return KNOT_ENOMEM;
+// }
+
+ /* Decode key from Base64. */
+ char decoded_key[B64BUFSIZE];
+
+ int decoded_key_size = b64_pton(key->secret, (uint8_t *)decoded_key,
+ B64BUFSIZE);
+ if (decoded_key_size < 0) {
+ dbg_tsig("TSIG: Could not decode Base64\n");
+ return KNOT_EMALF;
+ }
+
+ dbg_tsig("TSIG: decoded key size: %d\n", decoded_key_size);
+ dbg_tsig("TSIG: decoded key: '%*s'\n", decoded_key_size, decoded_key);
+
+ dbg_tsig("TSIG: using this wire for digest calculation\n");
+
+ //dbg_tsig_hex(wire, wire_len);
+
+ /* Compute digest. */
+ HMAC_CTX ctx;
+
+ switch (tsig_alg) {
+ case KNOT_TSIG_ALG_HMAC_MD5:
+ HMAC_Init(&ctx, decoded_key,
+ decoded_key_size, EVP_md5());
+ break;
+ default:
+ return KNOT_ENOTSUP;
+ } /* switch */
+
+ unsigned tmp_dig_len = *digest_len;
+ HMAC_Update(&ctx, (const unsigned char *)wire, wire_len);
+ HMAC_Final(&ctx, digest, &tmp_dig_len);
+ *digest_len = tmp_dig_len;
+
+ return KNOT_EOK;
+}
+
+static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr)
+{
+ if (!tsig_rr) {
+ return KNOT_EBADARG;
+ }
+
+ /* Get the time signed and fudge values. */
+ uint64_t time_signed = tsig_rdata_time_signed(tsig_rr);
+ if (time_signed == 0) {
+ return KNOT_TSIG_EBADTIME;
+ }
+ uint16_t fudge = tsig_rdata_fudge(tsig_rr);
+ if (fudge == 0) {
+ return KNOT_TSIG_EBADTIME;
+ }
+
+ /* Get the current time. */
+ time_t curr_time = time(NULL);
+
+ /*!< \todo bleeding eyes. */
+ if (difftime(curr_time, (time_t)time_signed) > fudge) {
+ return KNOT_TSIG_EBADTIME;
+ }
+
+ return KNOT_EOK;
+}
+
+static int knot_tsig_write_tsig_timers(uint8_t *wire,
+ const knot_rrset_t *tsig_rr)
+{
+ // put time signed
+ knot_wire_write_u48(wire, tsig_rdata_time_signed(tsig_rr));
+
+ // put fudge
+ knot_wire_write_u16(wire + 6, tsig_rdata_fudge(tsig_rr));
+
+ return KNOT_EOK;
+}
+
+static int knot_tsig_write_tsig_variables(uint8_t *wire,
+ const knot_rrset_t *tsig_rr)
+{
+ /* Copy TSIG variables - starting with key name. */
+ const knot_dname_t *tsig_owner = knot_rrset_owner(tsig_rr);
+ if (!tsig_owner) {
+ dbg_tsig("TSIG: write variables: no owner.\n");
+ return KNOT_EBADARG;
+ }
+
+ int offset = 0;
+
+ memcpy(wire + offset, knot_dname_name(tsig_owner),
+ sizeof(uint8_t) * knot_dname_size(tsig_owner));
+ dbg_tsig("TSIG: write variables: written owner (tsig alg): \n");
+ /*knot_rrset_class(tsig_rr));*/
+ dbg_tsig_hex_detail(wire + offset, knot_dname_size(tsig_owner));
+ offset += knot_dname_size(tsig_owner);
+
+ /*!< \todo which order? */
+
+ /* Copy class. */
+ knot_wire_write_u16(wire + offset, knot_rrset_class(tsig_rr));
+ dbg_tsig("TSIG: write variables: written CLASS: %u - ",
+ knot_rrset_class(tsig_rr));
+ dbg_tsig_hex_detail(wire + offset, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+
+ /* Copy TTL - always 0. */
+ knot_wire_write_u32(wire + offset, knot_rrset_ttl(tsig_rr));
+ dbg_tsig("TSIG: write variables: written TTL: %u - ",
+ knot_rrset_ttl(tsig_rr));
+ dbg_tsig_hex_detail(wire + offset, sizeof(uint32_t));
+ offset += sizeof(uint32_t);
+
+ /* Copy alg name. */
+ const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr);
+ if (!alg_name) {
+ dbg_tsig("TSIG: write variables: no algorithm name.\n");
+ return KNOT_EBADARG;
+ }
+// alg_name = knot_dname_new_from_str("HMAC-MD5.SIG-ALG.REG.INT.",
+ //strlen("HMAC-MD5.SIG-ALG.REG.INT."),
+ //NULL);
+
+ memcpy(wire + offset, knot_dname_name(alg_name),
+ sizeof(uint8_t) * knot_dname_size(alg_name));
+ offset += knot_dname_size(alg_name);
+ dbg_tsig_detail("TSIG: write variables: written alg name: %s\n",
+ knot_dname_to_str(alg_name));
+
+ /* Following data are written in network order. */
+ /* Time signed. */
+ knot_wire_write_u48(wire + offset, tsig_rdata_time_signed(tsig_rr));
+ offset += 6;
+ dbg_tsig_detail("TSIG: write variables: time signed: %llu - ",
+ tsig_rdata_time_signed(tsig_rr));
+ dbg_tsig_hex_detail(wire + offset - 6, 6);
+ /* Fudge. */
+ knot_wire_write_u16(wire + offset, tsig_rdata_fudge(tsig_rr));
+ offset += sizeof(uint16_t);
+ dbg_tsig_detail("TSIG: write variables: fudge: %hu\n",
+ tsig_rdata_fudge(tsig_rr));
+ /* TSIG error. */
+ knot_wire_write_u16(wire + offset, tsig_rdata_error(tsig_rr));
+ offset += sizeof(uint16_t);
+ /* Get other data length. */
+ uint16_t other_data_length = tsig_rdata_other_data_length(tsig_rr);
+ /* Get other data. */
+ const uint8_t *other_data = tsig_rdata_other_data(tsig_rr);
+ if (!other_data) {
+ dbg_tsig("TSIG: write variables: no other data.\n");
+ return KNOT_EBADARG;
+ }
+
+ /*
+ * We cannot write the whole other_data, as it contains its length in
+ * machine order.
+ */
+ knot_wire_write_u16(wire + offset, other_data_length);
+ offset += sizeof(uint16_t);
+
+ /* Skip the length. */
+ dbg_tsig_detail("Copying other data.\n");
+ memcpy(wire + offset, other_data, other_data_length);
+
+ return KNOT_EOK;
+}
+
+static int knot_tsig_wire_write_timers(uint8_t *wire,
+ const knot_rrset_t *tsig_rr)
+{
+ knot_wire_write_u48(wire, tsig_rdata_time_signed(tsig_rr));
+ knot_wire_write_u16(wire + 6, tsig_rdata_fudge(tsig_rr));
+
+ return KNOT_EOK;
+}
+
+int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len,
+ /*size_t msg_max_len, */const uint8_t *request_mac,
+ size_t request_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_rrset_t *tmp_tsig,
+ const knot_key_t *key)
+{
+ if (!msg || !key || digest_len == NULL) {
+ dbg_tsig("TSIG: create wire: bad args.\n");
+ return KNOT_EBADARG;
+ }
+
+ /* Create tmp TSIG. */
+ int ret = KNOT_EOK;
+// knot_rrset_t *tmp_tsig =
+// knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0);
+// if (!tmp_tsig) {
+// return KNOT_ENOMEM;
+// }
+
+// tsig_rdata_store_current_time(tmp_tsig);
+
+ /*
+ * Create tmp wire, it should contain message
+ * plus request mac plus tsig varibles.
+ */
+ dbg_tsig("Counting wire size: %zu, %zu, %zu.\n",
+ msg_len, request_mac_len,
+ tsig_rdata_tsig_variables_length(tmp_tsig));
+ size_t wire_len = sizeof(uint8_t) *
+ (msg_len + request_mac_len + ((request_mac_len > 0)
+ ? 2 : 0) +
+ tsig_rdata_tsig_variables_length(tmp_tsig));
+ uint8_t *wire = malloc(wire_len);
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ memset(wire, 0, wire_len);
+
+ uint8_t *pos = wire;
+
+ /* Copy the request MAC - should work even if NULL. */
+ if (request_mac_len > 0) {
+ dbg_tsig_detail("Copying request MAC size\n");
+ knot_wire_write_u16(pos, request_mac_len);
+ pos += 2;
+ }
+ dbg_tsig("Copying request mac.\n");
+ memcpy(pos, request_mac, sizeof(uint8_t) * request_mac_len);
+ dbg_tsig_detail("TSIG: create wire: request mac: ");
+ dbg_tsig_hex_detail(pos, request_mac_len);
+ pos += request_mac_len;
+ /* Copy the original message. */
+ dbg_tsig("Copying original message.\n");
+ memcpy(pos, msg, msg_len);
+ dbg_tsig_detail("TSIG: create wire: original message: \n");
+ //dbg_tsig_hex_detail(pos, msg_len);
+ pos += msg_len;
+ /* Copy TSIG variables. */
+ dbg_tsig("Writing TSIG variables.\n");
+ ret = knot_tsig_write_tsig_variables(pos, tmp_tsig);
+ if (ret != KNOT_EOK) {
+ dbg_tsig("TSIG: create wire: failed to write TSIG "
+ "variables: %s\n", knot_strerror(ret));
+ return ret;
+ }
+
+ /* Compute digest. */
+ ret = knot_tsig_compute_digest(wire, wire_len,
+ digest, digest_len, key);
+ if (ret != KNOT_EOK) {
+ dbg_tsig("TSIG: create wire: failed to compute digest: %s\n",
+ knot_strerror(ret));
+ *digest_len = 0;
+ return ret;
+ }
+
+// assert(digest_tmp_len > 0);
+ free(wire);
+
+// if (digest_tmp_len > *digest_len) {
+// *digest_len = 0;
+// return KNOT_ESPACE;
+// }
+
+// knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+
+ // everything went ok, save the digest to the output parameter
+// memcpy(digest, digest_tmp, digest_tmp_len);
+// *digest_len = digest_tmp_len;
+
+ return KNOT_EOK;
+}
+
+static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len,
+ const uint8_t *prev_mac,
+ size_t prev_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_rrset_t *tmp_tsig,
+ const knot_key_t *key)
+{
+ if (!msg || !key || digest_len == NULL) {
+ dbg_tsig("TSIG: create wire: bad args.\n");
+ return KNOT_EBADARG;
+ }
+
+ /* Create tmp TSIG. */
+ int ret = KNOT_EOK;
+
+ /*
+ * Create tmp wire, it should contain message
+ * plus request mac plus tsig varibles.
+ */
+ dbg_tsig("Counting wire size: %zu, %zu, %zu.\n",
+ msg_len, prev_mac_len,
+ tsig_rdata_tsig_timers_length());
+ size_t wire_len = sizeof(uint8_t) *
+ (msg_len + prev_mac_len +
+ tsig_rdata_tsig_timers_length());
+ uint8_t *wire = malloc(wire_len);
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ memset(wire, 0, wire_len);
+
+ /* Copy the request MAC - should work even if NULL. */
+ dbg_tsig("Copying request mac.\n");
+ memcpy(wire, prev_mac, sizeof(uint8_t) * prev_mac_len);
+ dbg_tsig_detail("TSIG: create wire: request mac: ");
+ dbg_tsig_hex_detail(wire, prev_mac_len);
+ /* Copy the original message. */
+ dbg_tsig("Copying original message.\n");
+ memcpy(wire + prev_mac_len, msg, msg_len);
+ dbg_tsig_detail("TSIG: create wire: original message: \n");
+ //dbg_tsig_hex_detail(wire + prev_mac_len, msg_len);
+ /* Copy TSIG variables. */
+
+ dbg_tsig("Writing TSIG timers.\n");
+ ret = knot_tsig_write_tsig_timers(wire + prev_mac_len + msg_len,
+ tmp_tsig);
+// ret = knot_tsig_write_tsig_variables(wire + prev_mac_len + msg_len,
+// tmp_tsig);
+ if (ret != KNOT_EOK) {
+ dbg_tsig("TSIG: create wire: failed to write TSIG "
+ "timers: %s\n", knot_strerror(ret));
+ return ret;
+ }
+
+ /* Compute digest. */
+ ret = knot_tsig_compute_digest(wire, wire_len,
+ digest, digest_len, key);
+ if (ret != KNOT_EOK) {
+ dbg_tsig("TSIG: create wire: failed to compute digest: %s\n",
+ knot_strerror(ret));
+ *digest_len = 0;
+ return ret;
+ }
+
+ free(wire);
+
+ return KNOT_EOK;
+}
+
+int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
+ size_t msg_max_len, const uint8_t *request_mac,
+ size_t request_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_key_t *key)
+{
+ if (!msg || !msg_len || !key || digest == NULL || digest_len == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_dname_t *key_name_copy = knot_dname_deep_copy(key->name);
+ if (!key_name_copy) {
+ dbg_tsig_detail("TSIG: key_name_copy = NULL\n");
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_t *tmp_tsig =
+ knot_rrset_new(key_name_copy,
+ KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0);
+ if (!tmp_tsig) {
+ dbg_tsig_detail("TSIG: tmp_tsig = NULL\n");
+ return KNOT_ENOMEM;
+ }
+
+ /* Create rdata for TSIG RR. */
+ knot_rdata_t *rdata = knot_rdata_new();
+ if (!rdata) {
+ dbg_tsig_detail("TSIG: rdata = NULL\n");
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_add_rdata(tmp_tsig, rdata);
+
+ /* Create items for TSIG RR. */
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(KNOT_RRTYPE_TSIG);
+ assert(desc);
+
+ knot_rdata_item_t *items =
+ malloc(sizeof(knot_rdata_item_t) * desc->length);
+ if (!items) {
+ dbg_tsig_detail("TSIG: items = NULL\n");
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ memset(items, 0, sizeof(knot_rdata_item_t) * desc->length);
+
+ int ret = knot_rdata_set_items(rdata, items, desc->length);
+ if (ret != KNOT_EOK) {
+ dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret));
+ return ret;
+ }
+ free(items);
+
+ tsig_rdata_set_alg(tmp_tsig, key->algorithm);
+ tsig_rdata_store_current_time(tmp_tsig);
+ tsig_rdata_set_fudge(tmp_tsig, 300);
+
+ /* Set original ID */
+ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
+
+ /* Set error */
+ /*! \todo [TSIG] Set error and other data if appropriate. */
+ tsig_rdata_set_tsig_error(tmp_tsig, 0);
+
+ /* Set other len. */
+ tsig_rdata_set_other_data(tmp_tsig, 0, 0);
+
+ uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
+ size_t digest_tmp_len = 0;
+
+ dbg_tsig_detail("tmp_tsig before sign_wire():\n");
+ knot_rrset_dump(tmp_tsig, 0);
+
+ ret = knot_tsig_create_sign_wire(msg, *msg_len, /*msg_max_len,*/
+ request_mac, request_mac_len,
+ digest_tmp, &digest_tmp_len,
+ tmp_tsig, key);
+ if (ret != KNOT_EOK) {
+ dbg_tsig("TSIG: could not create wire or sign wire: %s\n",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ /* Set the digest. */
+ size_t tsig_wire_len = msg_max_len - *msg_len;
+ int rr_count = 0;
+ tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);
+
+ //knot_rrset_dump(tmp_tsig, 1);
+
+ /* Write RRSet to wire */
+ ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
+ &tsig_wire_len, &rr_count);
+ if (ret != KNOT_EOK) {
+ dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret));
+ *digest_len = 0;
+ return ret;
+ }
+
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+
+ *msg_len += tsig_wire_len;
+
+ uint16_t arcount = knot_wire_get_arcount(msg);
+ knot_wire_set_arcount(msg, ++arcount);
+
+ // everything went ok, save the digest to the output parameter
+ memcpy(digest, digest_tmp, digest_tmp_len);
+ *digest_len = digest_tmp_len;
+
+ return KNOT_EOK;
+}
+
+int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const uint8_t *prev_digest, size_t prev_digest_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_key_t *key)
+{
+ if (!msg || !msg_len || !key || !key || !digest || !digest_len) {
+ return KNOT_EBADARG;
+ }
+
+ uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
+ size_t digest_tmp_len = 0;
+
+ /* Create tmp TSIG. */
+ knot_rrset_t *tmp_tsig =
+ knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0);
+ if (!tmp_tsig) {
+ return KNOT_ENOMEM;
+ }
+
+ tsig_rdata_store_current_time(tmp_tsig);
+
+ /* Create wire to be signed. */
+ size_t wire_len = prev_digest_len + *msg_len + KNOT_TSIG_TIMERS_LENGTH;
+ uint8_t *wire = malloc(wire_len);
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+ memset(wire, 0, wire_len);
+
+ /* Write previous digest. */
+ memcpy(wire, prev_digest, sizeof(uint8_t) * prev_digest_len);
+ /* Write original message. */
+ memcpy(msg + prev_digest_len, msg, *msg_len);
+ /* Write timers. */
+ knot_tsig_wire_write_timers(msg + prev_digest_len + *msg_len, tmp_tsig);
+
+ int ret = 0;
+ ret = knot_tsig_compute_digest(wire, wire_len,
+ digest_tmp, &digest_tmp_len, key);
+ if (ret != KNOT_EOK) {
+ *digest_len = 0;
+ return ret;
+ }
+
+ if (digest_tmp_len > *digest_len) {
+ *digest_len = 0;
+ return KNOT_ESPACE;
+ }
+
+ free(wire);
+
+ /* Set the MAC. */
+ tsig_rdata_set_mac(tmp_tsig, *digest_len, digest);
+
+ size_t tsig_wire_size = msg_max_len - *msg_len;
+ int rr_count = 0;
+ ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
+ &tsig_wire_size, &rr_count);
+ if (ret != KNOT_EOK) {
+ *digest_len = 0;
+ return ret;
+ }
+
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+
+ *msg_len += tsig_wire_size;
+ uint16_t arcount = knot_wire_get_arcount(msg);
+ knot_wire_set_arcount(msg, ++arcount);
+
+ memcpy(digest, digest_tmp, digest_tmp_len);
+ *digest_len = digest_tmp_len;
+
+ return KNOT_EOK;
+}
+
+static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *request_mac,
+ size_t request_mac_len,
+ const knot_key_t *tsig_key,
+ int use_times)
+{
+ if (!tsig_rr || !wire || !tsig_key) {
+ return KNOT_EBADARG;
+ }
+
+ /* Check time signed. */
+ int ret = knot_tsig_check_time_signed(tsig_rr);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ dbg_tsig("TSIG: time checked.\n");
+
+ /* Check that libknot knows the algorithm. */
+ ret = knot_tsig_check_algorithm(tsig_rr);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ dbg_tsig("TSIG: algorithm checked.\n");
+
+ /* Check that key is valid, ie. the same as given in args. */
+ ret = knot_tsig_check_key(tsig_rr, tsig_key);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ dbg_tsig("TSIG: key validity checked.\n");
+
+ /* Time OK algorithm OK, key name OK - do digest. */
+ /* Calculate the size of TSIG RR. */
+ size_t tsig_len = tsig_wire_actsize(tsig_rr);
+
+ dbg_tsig_detail("TSIG: check digest: wire before strip: \n");
+ //dbg_tsig_hex_detail(wire, size);
+
+ /* Strip the TSIG. */
+ size -= tsig_len;
+
+ dbg_tsig_detail("TSIG: check digest: wire after strip (stripped %zu):\n",
+ tsig_len);
+ //dbg_tsig_hex_detail(wire, size);
+
+ uint8_t *wire_to_sign = malloc(sizeof(uint8_t) * size);
+ if (!wire_to_sign) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ memset(wire_to_sign, 0, sizeof(uint8_t) * size);
+ memcpy(wire_to_sign, wire, size);
+
+ /* Decrease arcount. */
+ knot_wire_set_arcount(wire_to_sign,
+ knot_wire_get_arcount(wire_to_sign) - 1);
+
+ uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
+ size_t digest_tmp_len = 0;
+ assert(tsig_rr->rdata);
+
+ if (use_times) {
+ ret = knot_tsig_create_sign_wire_next(wire_to_sign, size,
+ request_mac, request_mac_len,
+ digest_tmp, &digest_tmp_len,
+ tsig_rr, tsig_key);
+ } else {
+ ret = knot_tsig_create_sign_wire(wire_to_sign, size,
+ request_mac, request_mac_len,
+ digest_tmp, &digest_tmp_len,
+ tsig_rr, tsig_key);
+ }
+
+ assert(tsig_rr->rdata);
+ free(wire_to_sign);
+
+ if (ret != KNOT_EOK) {
+ dbg_tsig("Failed to create wire format for checking: %s.\n",
+ knot_strerror(ret));
+ return ret;
+ }
+
+// uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
+// size_t digest_tmp_len = 0;
+// ret = knot_tsig_compute_digest(wire, size, digest_tmp,
+// &digest_tmp_len, tsig_key);
+// if (ret != KNOT_EOK) {
+// dbg_tsig("TSIG: digest could not be calculated\n");
+// return ret;
+// }
+
+ dbg_tsig("TSIG: digest calculated\n");
+
+ /* Compare MAC from TSIG RR RDATA with just computed digest. */
+
+ /*!< \todo move to function. */
+ const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr);
+ tsig_algorithm_t alg = tsig_alg_from_name(alg_name);
+
+ /*! \todo [TSIG] TRUNCATION */
+ uint16_t mac_length = tsig_rdata_mac_length(tsig_rr);
+ const uint8_t *tsig_mac = tsig_rdata_mac(tsig_rr);
+
+ if (mac_length != tsig_alg_digest_length(alg)) {
+ dbg_tsig("TSIG: calculated digest length and given length do not match!\n");
+ return KNOT_TSIG_EBADSIG;
+ }
+
+// assert(tsig_alg_digest_length(alg) == mac_length);
+
+ dbg_tsig("TSIG: calc digest : ");
+ dbg_tsig_hex(digest_tmp, digest_tmp_len);
+
+ dbg_tsig("TSIG: given digest: ");
+ dbg_tsig_hex(tsig_mac, mac_length);
+
+ if (strncasecmp((char *)(tsig_mac), (char *)digest_tmp,
+ mac_length) != 0) {
+ return KNOT_TSIG_EBADSIG;
+ }
+
+ return KNOT_EOK;
+}
+
+int knot_tsig_server_check(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const knot_key_t *tsig_key)
+{
+ dbg_tsig_verb("tsig_server_check()\n");
+ return knot_tsig_check_digest(tsig_rr, wire, size, NULL, 0, tsig_key, 0);
+}
+
+int knot_tsig_client_check(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *request_mac, size_t request_mac_len,
+ const knot_key_t *tsig_key)
+{
+ dbg_tsig_verb("tsig_client_check()\n");
+ return knot_tsig_check_digest(tsig_rr, wire, size, request_mac,
+ request_mac_len, tsig_key, 0);
+}
+
+int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *prev_digest,
+ size_t prev_digest_len,
+ const knot_key_t *tsig_key)
+{
+// return knot_tsig_client_check(tsig_rr, wire, size, prev_digest,
+// prev_digest_len, tsig_key);
+ dbg_tsig_verb("tsig_client_check_next()\n");
+ return knot_tsig_check_digest(tsig_rr, wire, size, prev_digest,
+ prev_digest_len, tsig_key, 1);
+ return KNOT_ENOTSUP;
+}
diff --git a/src/libknot/tsig-op.h b/src/libknot/tsig-op.h
new file mode 100644
index 0000000..b206dc7
--- /dev/null
+++ b/src/libknot/tsig-op.h
@@ -0,0 +1,161 @@
+/*!
+ * \file tsig-op.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief TSIG signing and validating.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_TSIG_OP_H_
+#define _KNOT_TSIG_OP_H_
+
+#include <stdint.h>
+
+#include "tsig.h"
+#include "rrset.h"
+
+/*!
+ * \brief Generate TSIG signature of a message.
+ *
+ * This function generates TSIG digest of the given message prepended with the
+ * given Request MAC (if any) and appended with TSIG Variables. It also appends
+ * the resulting TSIG RR to the message wire format and accordingly adjusts
+ * the message size.
+ *
+ * \note This function does not save the new digest to the 'digest' parameter
+ * unless everything went OK. This allows to sent the same buffer to
+ * the 'request_mac' and 'digest' parameters.
+ *
+ * \param msg Message to be signed.
+ * \param msg_len Size of the message in bytes.
+ * \param msg_max_len Maximum size of the message in bytes.
+ * \param request_mac Request MAC. (may be NULL).
+ * \param request_mac_len Size of the request MAC in bytes.
+ * \param digest Buffer to save the digest in.
+ * \param digest_len In: size of the buffer. Out: real size of the digest saved.
+ * \param tsig_rr RRSet containing the TSIG RR to be used. Data from the RR are
+ * appended to the signed message.
+ *
+ * \retval KNOT_EOK if everything went OK.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_sign(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const uint8_t *request_mac, size_t request_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_key_t *key);
+
+/*!
+ * \brief Generate TSIG signature of a 2nd or later message in a TCP session.
+ *
+ * This function generates TSIG digest of the given message prepended with the
+ * given Request MAC (if any) and appended with TSIG Variables. It also appends
+ * the resulting TSIG RR to the message wire format and accordingly adjusts
+ * the message size.
+ *
+ * \note This function does not save the new digest to the 'digest' parameter
+ * unless everything went OK. This allows to sent the same buffer to
+ * the 'request_mac' and 'digest' parameters.
+ *
+ * \param msg Message to be signed.
+ * \param msg_len Size of the message in bytes.
+ * \param msg_max_len Maximum size of the message in bytes.
+ * \param prev_digest Previous digest sent by the server in the session.
+ * \param prev_digest_len Size of the previous digest in bytes.
+ * \param digest Buffer to save the digest in.
+ * \param digest_len In: size of the buffer. Out: real size of the digest saved.
+ * \param tsig_rr RRSet containing the TSIG RR to be used. Data from the RR are
+ * appended to the signed message.
+ *
+ * \retval KNOT_EOK if successful.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ const uint8_t *prev_digest, size_t prev_digest_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_key_t *key);
+
+/*!
+ * \brief Checks incoming request.
+ *
+ * \param tsig_rr TSIG extracted from the packet.
+ * \param wire Wire format of the packet (including the TSIG RR).
+ * \param size Size of the wire format of packet in bytes.
+ *
+ * \retval KNOT_EOK If the signature is valid.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_server_check(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const knot_key_t *tsig_key);
+
+/*!
+ * \brief Checks incoming response.
+ *
+ * \param tsig_rr TSIG extracted from the packet.
+ * \param wire Wire format of the packet (including the TSIG RR).
+ * \param size Size of the wire format of packet in bytes.
+ * \param request_mac Request MAC. (may be NULL).
+ * \param request_mac_len Size of the request MAC in bytes.
+ *
+ * \retval KNOT_EOK If the signature is valid.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_client_check(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *request_mac, size_t request_mac_len,
+ const knot_key_t *key);
+
+/*!
+ * \brief Checks signature of 2nd or next packet in a TCP session.
+ *
+ * \param tsig_rr TSIG extracted from the packet.
+ * \param wire Wire format of the packet (including the TSIG RR).
+ * \param size Size of the wire format of packet in bytes.
+ * \param prev_digest Previous digest sent by the server in the session.
+ * \param prev_digest_len Size of the previous digest in bytes.
+ *
+ * \retval KNOT_EOK If the signature is valid.
+ * \retval TODO
+ *
+ * \todo This function should return TSIG errors by their codes which are
+ * positive values - this will be recognized by the caller.
+ */
+int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr,
+ const uint8_t *wire, size_t size,
+ const uint8_t *prev_digest,
+ size_t prev_digest_len,
+ const knot_key_t *key);
+
+#endif /* _KNOT_TSIG_H_ */
+
+/*! @} */
diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c
new file mode 100644
index 0000000..432539f
--- /dev/null
+++ b/src/libknot/tsig.c
@@ -0,0 +1,618 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <time.h>
+
+#include "tsig.h"
+#include "util/error.h"
+#include "util/debug.h"
+#include "common.h"
+#include "util/utils.h"
+#include "rrset.h"
+#include "rdata.h"
+#include "dname.h"
+
+/*! \brief TSIG algorithms table. */
+#define TSIG_ALG_TABLE_SIZE 8
+static knot_lookup_table_t tsig_alg_table[TSIG_ALG_TABLE_SIZE] = {
+ { KNOT_TSIG_ALG_GSS_TSIG, "gss-tsig." },
+ { KNOT_TSIG_ALG_HMAC_MD5, "hmac-md5.sig-alg.reg.int." },
+ { KNOT_TSIG_ALG_HMAC_SHA1, "hmac-sha1." },
+ { KNOT_TSIG_ALG_HMAC_SHA224, "hmac-sha224." },
+ { KNOT_TSIG_ALG_HMAC_SHA256, "hmac-sha256." },
+ { KNOT_TSIG_ALG_HMAC_SHA384, "hmac-sha384." },
+ { KNOT_TSIG_ALG_HMAC_SHA512, "hmac-sha512." },
+ { KNOT_TSIG_ALG_NULL, NULL }
+};
+
+int tsig_rdata_init(knot_rrset_t *tsig)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ /* Initializes rdata. */
+ tsig->rdata = knot_rdata_new();
+ if (!tsig->rdata) {
+ return KNOT_ENOMEM;
+ }
+
+ tsig->rdata->items =
+ malloc(sizeof(knot_rdata_item_t) * KNOT_TSIG_ITEM_COUNT);
+ if (!tsig->rdata->items) {
+ return KNOT_ENOMEM;
+ }
+
+ memset(tsig->rdata->items, 0,
+ sizeof(knot_rdata_item_t) * KNOT_TSIG_ITEM_COUNT);
+
+ return KNOT_EOK;
+}
+
+int tsig_rdata_set_alg_name(knot_rrset_t *tsig, knot_dname_t *alg_name)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rdata_t *rdata = knot_rrset_get_rdata(tsig);
+ if (!rdata) {
+ return KNOT_EBADARG;
+ }
+ assert(knot_rdata_item_count(rdata) >= 1);
+
+ knot_dname_t *alg_name_copy = knot_dname_deep_copy(alg_name);
+ if (!alg_name_copy) {
+ return KNOT_ENOMEM;
+ }
+
+ knot_rdata_item_set_dname(rdata, 0, alg_name_copy);
+
+ return KNOT_EOK;
+}
+
+int tsig_rdata_set_alg(knot_rrset_t *tsig, tsig_algorithm_t alg)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rdata_t *rdata = knot_rrset_get_rdata(tsig);
+ if (!rdata) {
+ return KNOT_EBADARG;
+ }
+ assert(knot_rdata_item_count(rdata) >= 1);
+
+ const char *alg_str = tsig_alg_to_str(alg);
+ knot_dname_t *alg_name_copy = knot_dname_new_from_str(alg_str,
+ strlen(alg_str),
+ 0);
+ if (!alg_name_copy) {
+ return KNOT_ENOMEM;
+ }
+
+ knot_rdata_item_set_dname(rdata, 0, alg_name_copy);
+
+ return KNOT_EOK;
+}
+
+int tsig_rdata_set_time_signed(knot_rrset_t *tsig, uint64_t time)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rdata_t *rdata = knot_rrset_get_rdata(tsig);
+ if (!rdata) {
+ return KNOT_EBADARG;
+ }
+ assert(knot_rdata_item_count(rdata) >= 2);
+
+ /* Create the wire format. */
+ uint16_t *wire = malloc(sizeof(uint8_t) * 6 + sizeof(uint16_t));
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ /* Write the length - 6. */
+ wire[0] = 6;
+ knot_wire_write_u48((uint8_t *)(wire + 1), time);
+
+ knot_rdata_item_set_raw_data(rdata, 1, wire);
+
+ return KNOT_EOK;
+}
+
+int tsig_rdata_set_fudge(knot_rrset_t *tsig, uint16_t fudge)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rdata_t *rdata = knot_rrset_get_rdata(tsig);
+ if (!rdata) {
+ return KNOT_EBADARG;
+ }
+ assert(knot_rdata_item_count(rdata) >= 3);
+
+ /* Create the wire format. */
+ uint16_t *wire = malloc(sizeof(uint8_t) * 2 + sizeof(uint16_t));
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ /* Write the length - 2. */
+ wire[0] = sizeof(uint16_t);
+ knot_wire_write_u16((uint8_t *)(wire + 1), fudge);
+
+ knot_rdata_item_set_raw_data(rdata, 2, wire);
+
+ return KNOT_EOK;
+}
+
+int tsig_rdata_set_mac(knot_rrset_t *tsig, uint16_t length, const uint8_t *mac)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rdata_t *rdata = knot_rrset_get_rdata(tsig);
+ if (!rdata) {
+ return KNOT_EBADARG;
+ }
+ assert(knot_rdata_item_count(rdata) >= 4);
+
+ /* Create the wire format. */
+ uint16_t *wire = malloc(sizeof(uint8_t) * length + 2 * sizeof(uint16_t));
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ /* Write the length. */
+ wire[0] = length + sizeof(uint16_t);
+ knot_wire_write_u16((uint8_t *)(wire + 1), length);
+ /* Copy the actual MAC. */
+ memcpy((uint8_t *)(wire + 2), mac, sizeof(uint8_t) * length);
+ knot_rdata_item_set_raw_data(rdata, 3, wire);
+
+ return KNOT_EOK;
+}
+
+int tsig_rdata_set_orig_id(knot_rrset_t *tsig, uint16_t id)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rdata_t *rdata = knot_rrset_get_rdata(tsig);
+ if (!rdata) {
+ return KNOT_EBADARG;
+ }
+ assert(knot_rdata_item_count(rdata) >= 5);
+
+ /* Create the wire format. */
+ uint16_t *wire = malloc(sizeof(uint8_t) * 2 + sizeof(uint16_t));
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ /* Write the length - 2. */
+ wire[0] = sizeof(uint16_t);
+ knot_wire_write_u16((uint8_t *)(wire + 1), id);
+
+ knot_rdata_item_set_raw_data(rdata, 4, wire);
+
+ return KNOT_EOK;
+}
+
+int tsig_rdata_set_tsig_error(knot_rrset_t *tsig, uint16_t tsig_error)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rdata_t *rdata = knot_rrset_get_rdata(tsig);
+ if (!rdata) {
+ return KNOT_EBADARG;
+ }
+ assert(knot_rdata_item_count(rdata) >= 6);
+
+ /* Create the wire format. */
+ uint16_t *wire = malloc(sizeof(uint8_t) * 2 + sizeof(uint16_t));
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ /* Write the length - 2. */
+ wire[0] = sizeof(uint16_t);
+ knot_wire_write_u16((uint8_t *)(wire + 1), tsig_error);
+
+ knot_rdata_item_set_raw_data(rdata, 5, wire);
+
+ return KNOT_EOK;
+}
+
+int tsig_rdata_set_other_data(knot_rrset_t *tsig, uint16_t length,
+ const uint8_t *other_data)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+
+ knot_rdata_t *rdata = knot_rrset_get_rdata(tsig);
+ if (!rdata) {
+ return KNOT_EBADARG;
+ }
+ assert(knot_rdata_item_count(rdata) >= 6);
+
+ /* Create the wire format. */
+ uint16_t *wire = malloc(sizeof(uint8_t) * length + 2 * sizeof(uint16_t));
+ if (!wire) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ /* Write the length. */
+ wire[0] = length + 2;
+ knot_wire_write_u16((uint8_t *)(wire + 1), length);
+ /* Copy the actual data. */
+ memcpy(wire + 2, other_data, sizeof(uint8_t) * length);
+ knot_rdata_item_set_raw_data(rdata, 6, wire);
+
+ return KNOT_EOK;
+}
+
+const knot_dname_t *tsig_rdata_alg_name(const knot_rrset_t *tsig)
+{
+ if (!tsig) {
+ return NULL;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata) {
+ dbg_tsig("TSIG: rdata: alg name: no rdata.\n");
+ return NULL;
+ }
+
+ if (knot_rdata_item_count(rdata) < 1) {
+ dbg_tsig("TSIG: rdata: alg name: not enough items.\n");
+ return NULL;
+ }
+
+ return knot_rdata_item(rdata, 0)->dname;
+}
+
+tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig)
+{
+ /*! \todo [TSIG] Implement me. */
+ return KNOT_TSIG_ALG_HMAC_MD5;
+}
+
+uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig)
+{
+ /*!< \note How about assert. Or maybe change API??? */
+ if (!tsig) {
+ return 0;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata) {
+ return 0;
+ }
+
+ if (knot_rdata_item_count(rdata) < 2) {
+ return 0;
+ }
+
+ uint16_t *wire = knot_rdata_item(rdata, 1)->raw_data;
+ assert(wire[0] == 6);
+ /* Skip the size. */
+ wire++;
+
+ return knot_wire_read_u48((uint8_t *)wire);
+}
+
+uint16_t tsig_rdata_fudge(const knot_rrset_t *tsig)
+{
+ /*!< \note How about assert. Or maybe change API??? */
+ if (!tsig) {
+ return 0;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata) {
+ return 0;
+ }
+
+ if (knot_rdata_item_count(rdata) < 3) {
+ return 0;
+ }
+
+ uint16_t *wire = knot_rdata_item(rdata, 2)->raw_data;
+ assert(wire[0] == 2);
+ /* Skip the size. */
+ wire++;
+
+ return knot_wire_read_u16((uint8_t *)wire);
+}
+
+const uint8_t *tsig_rdata_mac(const knot_rrset_t *tsig)
+{
+ /*!< \note How about assert. Or maybe change API??? */
+ if (!tsig) {
+ return 0;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata) {
+ return 0;
+ }
+
+ if (knot_rdata_item_count(rdata) < 4) {
+ return 0;
+ }
+
+ return (uint8_t*)(knot_rdata_item(rdata, 3)->raw_data + 2);
+}
+
+size_t tsig_rdata_mac_length(const knot_rrset_t *tsig)
+{
+ if (!tsig) {
+ return 0;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata || knot_rdata_item_count(rdata) < 4) {
+ return 0;
+ }
+
+ return knot_wire_read_u16(
+ (uint8_t *)(knot_rdata_item(rdata, 3)->raw_data + 1));
+}
+
+uint16_t tsig_rdata_orig_id(const knot_rrset_t *tsig)
+{
+ /*!< \note How about assert. Or maybe change API??? */
+ if (!tsig) {
+ return 0;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata) {
+ return 0;
+ }
+
+ if (knot_rdata_item_count(rdata) < 5) {
+ return 0;
+ }
+
+ uint16_t *wire = knot_rdata_item(rdata, 4)->raw_data;
+ assert(wire[0] == 2);
+ /* Skip the size. */
+ wire++;
+
+ return knot_wire_read_u16((uint8_t *)wire);
+}
+
+uint16_t tsig_rdata_error(const knot_rrset_t *tsig)
+{
+ /*!< \note How about assert. Or maybe change API??? */
+ if (!tsig) {
+ return 0;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata) {
+ return 0;
+ }
+
+ if (knot_rdata_item_count(rdata) < 6) {
+ return 0;
+ }
+
+ uint16_t *wire = knot_rdata_item(rdata, 5)->raw_data;
+ assert(wire[0] == 2);
+ /* Skip the size. */
+ wire++;
+
+ return knot_wire_read_u16((uint8_t *)wire);
+}
+
+const uint8_t *tsig_rdata_other_data(const knot_rrset_t *tsig)
+{
+ /*!< \note How about assert. Or maybe change API??? */
+ if (!tsig) {
+ return 0;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata) {
+ return 0;
+ }
+
+ if (knot_rdata_item_count(rdata) < 7) {
+ return 0;
+ }
+
+ return (uint8_t *)(knot_rdata_item(rdata, 6)->raw_data + 2);
+}
+
+uint16_t tsig_rdata_other_data_length(const knot_rrset_t *tsig)
+{
+ /*!< \note How about assert. Or maybe change API??? */
+ if (!tsig) {
+ return 0;
+ }
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(tsig);
+ if (!rdata) {
+ return 0;
+ }
+
+ if (knot_rdata_item_count(rdata) < 7) {
+ return 0;
+ }
+
+ return knot_wire_read_u16((uint8_t *)
+ (knot_rdata_item(rdata, 6)->raw_data + 1));
+}
+
+int tsig_alg_from_name(const knot_dname_t *alg_name)
+{
+ if (!alg_name) {
+ return 0;
+ }
+
+ char *name = knot_dname_to_str(alg_name);
+ if (!name) {
+ return 0;
+ }
+
+ knot_lookup_table_t *found =
+ knot_lookup_by_name(tsig_alg_table, name);
+
+ if (!found) {
+ dbg_tsig("Unknown algorithm: %s \n", name);
+ free(name);
+ return 0;
+ }
+
+ free(name);
+
+ return found->id;
+}
+
+uint16_t tsig_alg_digest_length(tsig_algorithm_t alg)
+{
+ switch (alg) {
+ case KNOT_TSIG_ALG_GSS_TSIG:
+ return KNOT_TSIG_ALG_DIG_LENGTH_GSS_TSIG;
+ case KNOT_TSIG_ALG_HMAC_MD5:
+ return KNOT_TSIG_ALG_DIG_LENGTH_HMAC_MD5;
+ case KNOT_TSIG_ALG_HMAC_SHA1:
+ return KNOT_TSIG_ALG_DIG_LENGTH_SHA1;
+ case KNOT_TSIG_ALG_HMAC_SHA224:
+ return KNOT_TSIG_ALG_DIG_LENGTH_SHA224;
+ case KNOT_TSIG_ALG_HMAC_SHA256:
+ return KNOT_TSIG_ALG_DIG_LENGTH_SHA384;
+ case KNOT_TSIG_ALG_HMAC_SHA512:
+ return KNOT_TSIG_ALG_DIG_LENGTH_SHA512;
+ default:
+ return 0;
+ } /* switch(alg) */
+}
+
+size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig)
+{
+ /* Key name, Algorithm name and Other data have variable lengths. */
+ const knot_dname_t *key_name = knot_rrset_owner(tsig);
+ if (!key_name) {
+ return 0;
+ }
+
+ const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig);
+ if (!alg_name) {
+ return 0;
+ }
+
+// dbg_tsig_detail("key_name: %.*s (size: %u) alg_name: %.*s (size: %u)\n", knot_dname_size(key_name),
+// key_name->name, alg_name->size, alg_name->name,
+// key_name->size, alg_name->size);
+
+// dbg_tsig_hex_detail(key_name->name, key_name->size);
+// dbg_tsig_hex_detail(alg_name->name, alg_name->size);
+
+ uint16_t other_data_length = tsig_rdata_other_data_length(tsig);
+
+ return knot_dname_size(key_name) + knot_dname_size(alg_name) +
+ other_data_length + KNOT_TSIG_VARIABLES_LENGTH;
+}
+
+size_t tsig_rdata_tsig_timers_length()
+{
+ return KNOT_TSIG_TIMERS_LENGTH;
+}
+
+
+int tsig_rdata_store_current_time(knot_rrset_t *tsig)
+{
+ if (!tsig) {
+ return KNOT_EBADARG;
+ }
+ time_t curr_time = time(NULL);
+ /*!< \todo bleeding eyes. */
+ tsig_rdata_set_time_signed(tsig, (uint64_t)curr_time);
+ return KNOT_EOK;
+}
+
+const char* tsig_alg_to_str(tsig_algorithm_t alg)
+{
+ for (unsigned i = 0; i < TSIG_ALG_TABLE_SIZE; ++i) {
+ if (tsig_alg_table[i].id == alg) {
+ return tsig_alg_table[i].name;
+ }
+ }
+
+ return "";
+}
+
+size_t tsig_wire_maxsize(const knot_key_t* key)
+{
+ size_t alg_name_size = strlen(tsig_alg_to_str(key->algorithm)) + 1;
+
+ return knot_dname_size(key->name) +
+ sizeof(uint16_t) + /* TYPE */
+ sizeof(uint16_t) + /* CLASS */
+ sizeof(uint32_t) + /* TTL */
+ sizeof(uint16_t) + /* RDLENGTH */
+ alg_name_size + /* Alg. name */
+ 6 * sizeof(uint8_t) + /* Time signed */
+ sizeof(uint16_t) + /* Fudge */
+ sizeof(uint16_t) + /* MAC size */
+ tsig_alg_digest_length(key->algorithm) + /* MAC */
+ sizeof(uint16_t) + /* Original ID */
+ sizeof(uint16_t) + /* Error */
+ sizeof(uint16_t) + /* Other len */
+ 6* sizeof(uint8_t); /* uint48_t in case of BADTIME RCODE */
+}
+
+size_t tsig_wire_actsize(const knot_rrset_t *tsig)
+{
+ return knot_dname_size(knot_rrset_owner(tsig)) +
+ sizeof(uint16_t) + /* TYPE */
+ sizeof(uint16_t) + /* CLASS */
+ sizeof(uint32_t) + /* TTL */
+ sizeof(uint16_t) + /* RDLENGTH */
+ knot_dname_size(tsig_rdata_alg_name(tsig)) +
+ 6 * sizeof(uint8_t) + /* Time signed */
+ sizeof(uint16_t) + /* Fudge */
+ sizeof(uint16_t) + /* MAC size */
+ tsig_rdata_mac_length(tsig) +
+ sizeof(uint16_t) + /* Original ID */
+ sizeof(uint16_t) + /* Error */
+ sizeof(uint16_t) + /* Other len */
+ tsig_rdata_other_data_length(tsig);
+}
+
diff --git a/src/libknot/tsig.h b/src/libknot/tsig.h
new file mode 100644
index 0000000..eafcfab
--- /dev/null
+++ b/src/libknot/tsig.h
@@ -0,0 +1,145 @@
+/*!
+ * \file tsig.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief TSIG manipulation.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_TSIG_H_
+#define _KNOT_TSIG_H_
+
+#include <stdint.h>
+
+#include "rrset.h"
+#include "util/utils.h"
+
+/* The assigned numbers should not begin with 0 - reserved for error. */
+enum tsig_algorithm {
+ KNOT_TSIG_ALG_NULL = 0,
+ KNOT_TSIG_ALG_GSS_TSIG = 128, /*!< \brief gss-tsig. */
+ KNOT_TSIG_ALG_HMAC_MD5, /*!< \brief HMAC-MD5.SIG-ALG.REG.INT. */
+ KNOT_TSIG_ALG_HMAC_SHA1, /*!< \brief hmac-sha1. */
+ KNOT_TSIG_ALG_HMAC_SHA224, /*!< \brief hmac-sha224. */
+ KNOT_TSIG_ALG_HMAC_SHA256, /*!< \brief hmac-sha256. */
+ KNOT_TSIG_ALG_HMAC_SHA384, /*!< \brief hmac-sha384. */
+ KNOT_TSIG_ALG_HMAC_SHA512 /*!< \brief hmac-sha512. */
+};
+
+typedef enum tsig_algorithm tsig_algorithm_t;
+
+struct knot_key {
+ knot_dname_t *name; /*!< Key name. */
+ tsig_algorithm_t algorithm; /*!< Key algorithm. */
+ char *secret; /*!< Key data. */
+ size_t secret_size; /*!< Key length. */
+};
+
+typedef struct knot_key knot_key_t;
+
+/*!< \todo FIND ALG LENGTHS */
+enum tsig_algorithm_digest_length {
+ KNOT_TSIG_ALG_DIG_LENGTH_GSS_TSIG = 0,
+ KNOT_TSIG_ALG_DIG_LENGTH_HMAC_MD5 = 16,
+ KNOT_TSIG_ALG_DIG_LENGTH_SHA1 = 0,
+ KNOT_TSIG_ALG_DIG_LENGTH_SHA224 = 0,
+ KNOT_TSIG_ALG_DIG_LENGTH_SHA256 = 0,
+ KNOT_TSIG_ALG_DIG_LENGTH_SHA384 = 0,
+ KNOT_TSIG_ALG_DIG_LENGTH_SHA512 = 0
+};
+
+enum tsig_consts {
+ KNOT_TSIG_ITEM_COUNT = 7,
+ KNOT_TSIG_VARIABLES_LENGTH = sizeof(uint16_t) // class
+ + sizeof(uint32_t) // ttl
+ + 6 // time signed
+ + sizeof(uint16_t) // fudge
+ + sizeof(uint16_t) // error
+ + sizeof(uint16_t),// other data length
+ KNOT_TSIG_TIMERS_LENGTH = sizeof(uint16_t) //fugde
+ + 6 // time signed
+};
+
+/*! TSIG errors are defined in util/error.h
+ * and present negative value of the TSIG error to
+ * comply with other parts of the library.
+ *
+ * KNOT_TSIG_EBADSIG = -16
+ * KNOT_TSIG_EBADKEY = -17
+ * KNOT_TSIG_EBADTIME = -18
+ */
+
+/*!
+ * \note Uses the given domain name, do not deallocate it!
+ */
+int tsig_rdata_set_alg_name(knot_rrset_t *tsig, knot_dname_t *alg_name);
+int tsig_rdata_set_alg(knot_rrset_t *tsig, tsig_algorithm_t alg);
+int tsig_rdata_set_time_signed(knot_rrset_t *tsig, uint64_t time);
+int tsig_rdata_store_current_time(knot_rrset_t *tsig);
+int tsig_rdata_set_fudge(knot_rrset_t *tsig, uint16_t fudge);
+int tsig_rdata_set_mac(knot_rrset_t *tsig, uint16_t length,
+ const uint8_t *mac);
+int tsig_rdata_set_orig_id(knot_rrset_t *tsig, uint16_t id);
+int tsig_rdata_set_tsig_error(knot_rrset_t *tsig, uint16_t tsig_error);
+int tsig_rdata_set_other_data(knot_rrset_t *tsig, uint16_t length,
+ const uint8_t *other_data);
+
+const knot_dname_t *tsig_rdata_alg_name(const knot_rrset_t *tsig);
+tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig);
+uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig);
+uint16_t tsig_rdata_fudge(const knot_rrset_t *tsig);
+const uint8_t *tsig_rdata_mac(const knot_rrset_t *tsig);
+size_t tsig_rdata_mac_length(const knot_rrset_t *tsig);
+uint16_t tsig_rdata_orig_id(const knot_rrset_t *tsig);
+uint16_t tsig_rdata_error(const knot_rrset_t *tsig);
+const uint8_t *tsig_rdata_other_data(const knot_rrset_t *tsig);
+uint16_t tsig_rdata_other_data_length(const knot_rrset_t *tsig);
+size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig);
+
+size_t tsig_rdata_tsig_timers_length();
+
+int tsig_alg_from_name(const knot_dname_t *name);
+
+/*!
+ * \brief Convert TSIG algorithm identifier to name.
+ *
+ * \param alg TSIG algorithm identifier.
+ *
+ * \retval TSIG algorithm string name.
+ * \retval Empty string if undefined.
+ */
+const char* tsig_alg_to_str(tsig_algorithm_t alg);
+
+uint16_t tsig_alg_digest_length(tsig_algorithm_t alg);
+
+/*!
+ * \brief Return TSIG RRSET maximum wire size for given algorithm.
+ *
+ * \param key Signing key descriptor.
+ *
+ * \return RRSET wire size.
+ */
+size_t tsig_wire_maxsize(const knot_key_t *key);
+size_t tsig_wire_actsize(const knot_rrset_t *tsig);
+
+#endif /* _KNOT_TSIG_H_ */
+
+/*! @} */
diff --git a/src/libknot/updates/changesets.c b/src/libknot/updates/changesets.c
new file mode 100644
index 0000000..cf9e6a0
--- /dev/null
+++ b/src/libknot/updates/changesets.c
@@ -0,0 +1,296 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "updates/changesets.h"
+
+#include "rrset.h"
+#include "util/error.h"
+
+static const size_t KNOT_CHANGESET_COUNT = 5;
+static const size_t KNOT_CHANGESET_STEP = 5;
+static const size_t KNOT_CHANGESET_RRSET_COUNT = 5;
+static const size_t KNOT_CHANGESET_RRSET_STEP = 5;
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_changeset_check_count(knot_rrset_t ***rrsets, size_t count,
+ size_t *allocated)
+{
+ /* Check if allocated is sufficient. */
+ if (count <= *allocated) {
+ return KNOT_EOK;
+ }
+
+ /* How many steps is needed to content count? */
+ size_t extra = (count - *allocated) % KNOT_CHANGESET_RRSET_STEP;
+ extra = (extra + 1) * KNOT_CHANGESET_RRSET_STEP;
+
+ /* Allocate new memory block. */
+ const size_t item_len = sizeof(knot_rrset_t *);
+ const size_t new_count = *allocated + extra;
+ knot_rrset_t **rrsets_new = malloc(new_count * item_len);
+ if (rrsets_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Clear old memory block and copy old data. */
+ memset(rrsets_new, 0, new_count * item_len);
+ memcpy(rrsets_new, *rrsets, (*allocated) * item_len);
+
+ /* Replace old rrsets. */
+ free(*rrsets);
+ *rrsets = rrsets_new;
+ *allocated = new_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_changeset_rrsets_match(const knot_rrset_t *rrset1,
+ const knot_rrset_t *rrset2)
+{
+ return knot_rrset_compare(rrset1, rrset2, KNOT_RRSET_COMPARE_HEADER)
+ && (knot_rrset_type(rrset1) != KNOT_RRTYPE_RRSIG
+ || knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(rrset1))
+ == knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(rrset2)));
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_changeset_allocate(knot_changesets_t **changesets)
+{
+ // create new changesets
+ *changesets = (knot_changesets_t *)(malloc(sizeof(knot_changesets_t)));
+ if (*changesets == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ memset(*changesets, 0, sizeof(knot_changesets_t));
+
+ return knot_changesets_check_size(*changesets);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_changeset_add_rrset(knot_rrset_t ***rrsets,
+ size_t *count, size_t *allocated,
+ knot_rrset_t *rrset)
+{
+ int ret = knot_changeset_check_count(rrsets, *count + 1, allocated);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ (*rrsets)[*count] = rrset;
+ *count = *count + 1;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_changeset_add_rr(knot_rrset_t ***rrsets, size_t *count,
+ size_t *allocated, knot_rrset_t *rr)
+{
+ // try to find the RRSet in the list of RRSets, but search backwards
+ // as it is probable that the last RRSet is the one to which the RR
+ // belongs
+ int i = *count - 1;
+
+ while (i >= 0 && !knot_changeset_rrsets_match((*rrsets)[i], rr)) {
+ --i;
+ }
+
+ if (i >= 0) {
+ // found RRSet to merge the new one into
+ if (knot_rrset_merge((void **)&(*rrsets)[i],
+ (void **)&rr) != KNOT_EOK) {
+ return KNOT_ERROR;
+ }
+
+ // remove the RR
+ /*! \todo does this make sense? */
+ knot_rrset_free(&rr); // used to be deep free with all 1's
+
+ return KNOT_EOK;
+ } else {
+ return knot_changeset_add_rrset(rrsets, count, allocated, rr);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_changeset_add_new_rr(knot_changeset_t *changeset,
+ knot_rrset_t *rrset,
+ xfrin_changeset_part_t part)
+{
+ knot_rrset_t ***rrsets = NULL;
+ size_t *count = NULL;
+ size_t *allocated = NULL;
+
+ switch (part) {
+ case XFRIN_CHANGESET_ADD:
+ rrsets = &changeset->add;
+ count = &changeset->add_count;
+ allocated = &changeset->add_allocated;
+ break;
+ case XFRIN_CHANGESET_REMOVE:
+ rrsets = &changeset->remove;
+ count = &changeset->remove_count;
+ allocated = &changeset->remove_allocated;
+ break;
+ default:
+ assert(0);
+ }
+
+ assert(rrsets != NULL);
+ assert(count != NULL);
+ assert(allocated != NULL);
+
+ int ret = knot_changeset_add_rr(rrsets, count, allocated, rrset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_changeset_store_soa(knot_rrset_t **chg_soa,
+ uint32_t *chg_serial, knot_rrset_t *soa)
+{
+ *chg_soa = soa;
+ *chg_serial = knot_rdata_soa_serial(knot_rrset_rdata(soa));
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa,
+ xfrin_changeset_part_t part)
+{
+ switch (part) {
+ case XFRIN_CHANGESET_ADD:
+ knot_changeset_store_soa(&changeset->soa_to,
+ &changeset->serial_to, soa);
+ break;
+ case XFRIN_CHANGESET_REMOVE:
+ knot_changeset_store_soa(&changeset->soa_from,
+ &changeset->serial_from, soa);
+ break;
+ default:
+ assert(0);
+ }
+
+ /*! \todo Remove return value? */
+ return KNOT_EOK;
+}
+
+/*---------------------------------------------------------------------------*/
+
+int knot_changesets_check_size(knot_changesets_t *changesets)
+{
+ /* Check if allocated is sufficient. */
+ if (changesets->count <= changesets->allocated) {
+ return KNOT_EOK;
+ }
+
+ /* How many steps is needed to content count? */
+ size_t extra = (changesets->count - changesets->allocated) % KNOT_CHANGESET_STEP;
+ extra = (extra + 1) * KNOT_CHANGESET_STEP;
+
+ /* Allocate new memory block. */
+ const size_t item_len = sizeof(knot_changeset_t);
+ size_t new_count = (changesets->allocated + extra);
+ knot_changeset_t *sets = malloc(new_count * item_len);
+ if (sets == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Clear old memory block and copy old data. */
+ memset(sets, 0, new_count * item_len);
+ memcpy(sets, changesets->sets, changesets->allocated * item_len);
+
+ /* Replace old changesets. */
+ free(changesets->sets);
+ changesets->sets = sets;
+ changesets->allocated = new_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_free_changeset(knot_changeset_t **changeset)
+{
+ /* XXX XXX investigate wrong frees. */
+ assert((*changeset)->add_allocated >= (*changeset)->add_count);
+ assert((*changeset)->remove_allocated >= (*changeset)->remove_count);
+ assert((*changeset)->allocated >= (*changeset)->size);
+
+ int j;
+ for (j = 0; j < (*changeset)->add_count; ++j) {
+ knot_rrset_deep_free(&(*changeset)->add[j], 1, 1, 1);
+ }
+ free((*changeset)->add);
+
+ for (j = 0; j < (*changeset)->remove_count; ++j) {
+ knot_rrset_deep_free(&(*changeset)->remove[j], 1, 1, 1);
+ }
+ free((*changeset)->remove);
+
+ knot_rrset_deep_free(&(*changeset)->soa_from, 1, 1, 1);
+ knot_rrset_deep_free(&(*changeset)->soa_to, 1, 1, 1);
+
+ free((*changeset)->data);
+
+
+ *changeset = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_free_changesets(knot_changesets_t **changesets)
+{
+ if (changesets == NULL || *changesets == NULL) {
+ return;
+ }
+
+ assert((*changesets)->allocated >= (*changesets)->count);
+
+ for (int i = 0; i < (*changesets)->count; ++i) {
+ knot_changeset_t *ch = &(*changesets)->sets[i];
+ knot_free_changeset(&ch);
+ }
+
+ free((*changesets)->sets);
+
+ knot_rrset_deep_free(&(*changesets)->first_soa, 1, 1, 1);
+
+ free(*changesets);
+ *changesets = NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+
+
diff --git a/src/libknot/updates/changesets.h b/src/libknot/updates/changesets.h
new file mode 100644
index 0000000..e8d5e39
--- /dev/null
+++ b/src/libknot/updates/changesets.h
@@ -0,0 +1,102 @@
+/*!
+ * \file changesets.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Structure for representing IXFR/DDNS changeset and its API.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_CHANGESETS_H_
+#define _KNOT_CHANGESETS_H_
+
+#include "rrset.h"
+
+/*! \todo Changeset must be serializable/deserializable, so
+ * all data and pointers have to be changeset-exclusive,
+ * or more advanced structure serialization scheme has to be
+ * implemented.
+ *
+ * \todo Preallocation of space for changeset.
+ */
+typedef struct {
+ knot_rrset_t *soa_from;
+ knot_rrset_t **remove;
+ size_t remove_count;
+ size_t remove_allocated;
+
+ knot_rrset_t *soa_to;
+ knot_rrset_t **add;
+ size_t add_count;
+ size_t add_allocated;
+
+ uint8_t *data;
+ size_t size;
+ size_t allocated;
+ uint32_t serial_from;
+ uint32_t serial_to;
+} knot_changeset_t;
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct {
+ knot_changeset_t *sets;
+ size_t count;
+ size_t allocated;
+ knot_rrset_t *first_soa;
+} knot_changesets_t;
+
+/*----------------------------------------------------------------------------*/
+
+typedef enum {
+ XFRIN_CHANGESET_ADD,
+ XFRIN_CHANGESET_REMOVE
+} xfrin_changeset_part_t;
+
+/*----------------------------------------------------------------------------*/
+
+int knot_changeset_allocate(knot_changesets_t **changesets);
+
+int knot_changeset_add_rrset(knot_rrset_t ***rrsets,
+ size_t *count, size_t *allocated,
+ knot_rrset_t *rrset);
+
+int knot_changeset_add_rr(knot_rrset_t ***rrsets, size_t *count,
+ size_t *allocated, knot_rrset_t *rr);
+
+int knot_changeset_add_new_rr(knot_changeset_t *changeset,
+ knot_rrset_t *rrset,
+ xfrin_changeset_part_t part);
+
+void knot_changeset_store_soa(knot_rrset_t **chg_soa,
+ uint32_t *chg_serial, knot_rrset_t *soa);
+
+int knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa,
+ xfrin_changeset_part_t part);
+
+int knot_changesets_check_size(knot_changesets_t *changesets);
+
+void knot_free_changeset(knot_changeset_t **changeset);
+
+void knot_free_changesets(knot_changesets_t **changesets);
+
+#endif /* _KNOT_CHANGESETS_H_ */
+
+/*! @} */
diff --git a/src/libknot/updates/ddns.c b/src/libknot/updates/ddns.c
new file mode 100644
index 0000000..4c6ab7b
--- /dev/null
+++ b/src/libknot/updates/ddns.c
@@ -0,0 +1,638 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "updates/ddns.h"
+#include "updates/changesets.h"
+#include "util/debug.h"
+#include "packet/packet.h"
+#include "util/error.h"
+#include "consts.h"
+
+/*----------------------------------------------------------------------------*/
+// Copied from XFR - maybe extract somewhere else
+static int knot_ddns_prereq_check_rrsets(knot_rrset_t ***rrsets,
+ size_t *count, size_t *allocated)
+{
+ int new_count = 0;
+ if (*count == *allocated) {
+ new_count = *allocated * 2;
+ }
+
+ knot_rrset_t **rrsets_new =
+ (knot_rrset_t **)calloc(new_count, sizeof(knot_rrset_t *));
+ if (rrsets_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(rrsets_new, *rrsets, *count);
+ *rrsets = rrsets_new;
+ *allocated = new_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_prereq_check_dnames(knot_dname_t ***dnames,
+ size_t *count, size_t *allocated)
+{
+ int new_count = 0;
+ if (*count == *allocated) {
+ new_count = *allocated * 2;
+ }
+
+ knot_dname_t **dnames_new =
+ (knot_dname_t **)calloc(new_count, sizeof(knot_dname_t *));
+ if (dnames_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ memcpy(dnames_new, *dnames, *count);
+ *dnames = dnames_new;
+ *allocated = new_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_add_prereq_rrset(const knot_rrset_t *rrset,
+ knot_rrset_t ***rrsets,
+ size_t *count, size_t *allocd)
+{
+ // check if such RRSet is not already there and merge if needed
+ int ret;
+ for (int i = 0; i < *count; ++i) {
+ if (knot_rrset_compare(rrset, (*rrsets)[i],
+ KNOT_RRSET_COMPARE_HEADER) == 0) {
+ ret = knot_rrset_merge((void **)&((*rrsets)[i]),
+ (void **)&rrset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else {
+ return KNOT_EOK;
+ }
+ }
+ }
+
+ // if we are here, the RRSet was not found
+ ret = knot_ddns_prereq_check_rrsets(rrsets, count, allocd);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_rrset_t *new_rrset = NULL;
+ ret = knot_rrset_deep_copy(rrset, &new_rrset);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ (*rrsets)[(*count)++] = new_rrset;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_add_prereq_dname(const knot_dname_t *dname,
+ knot_dname_t ***dnames,
+ size_t *count, size_t *allocd)
+{
+ // we do not have to check if the name is not already there
+ // if it is, we will just check it twice in the zone
+
+ int ret = knot_ddns_prereq_check_dnames(dnames, count, allocd);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ knot_dname_t *dname_new = knot_dname_deep_copy(dname);
+ if (dname_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ (*dnames)[(*count)++] = dname_new;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs,
+ const knot_rrset_t *rrset, uint16_t qclass)
+{
+ assert(prereqs != NULL);
+ assert(rrset != NULL);
+
+ if (knot_rrset_ttl(rrset) != 0) {
+ return KNOT_EMALF;
+ }
+
+ int ret;
+
+ if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) {
+ if (knot_rrset_rdata(rrset) != NULL) {
+ return KNOT_EMALF;
+ }
+ if (knot_rrset_type(rrset) == KNOT_RRTYPE_ANY) {
+ ret = knot_ddns_add_prereq_dname(
+ knot_rrset_owner(rrset), &prereqs->in_use,
+ &prereqs->in_use_count,
+ &prereqs->in_use_allocd);
+ } else {
+ ret = knot_ddns_add_prereq_rrset(rrset,
+ &prereqs->exist,
+ &prereqs->exist_count,
+ &prereqs->exist_allocd);
+ }
+ } else if (knot_rrset_class(rrset) == KNOT_CLASS_NONE) {
+ if (knot_rrset_rdata(rrset) != NULL) {
+ return KNOT_EMALF;
+ }
+ if (knot_rrset_type(rrset) == KNOT_RRTYPE_ANY) {
+ ret = knot_ddns_add_prereq_dname(
+ knot_rrset_owner(rrset), &prereqs->not_in_use,
+ &prereqs->not_in_use_count,
+ &prereqs->not_in_use_allocd);
+ } else {
+ ret = knot_ddns_add_prereq_rrset(rrset,
+ &prereqs->not_exist,
+ &prereqs->not_exist_count,
+ &prereqs->not_exist_allocd);
+ }
+ } else if (knot_rrset_class(rrset) == qclass) {
+ ret = knot_ddns_add_prereq_rrset(rrset,
+ &prereqs->exist_full,
+ &prereqs->exist_full_count,
+ &prereqs->exist_full_allocd);
+ } else {
+ return KNOT_EMALF;
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_add_update(knot_changeset_t *changeset,
+ const knot_rrset_t *rrset, uint16_t qclass)
+{
+ assert(changeset != NULL);
+ assert(rrset != NULL);
+
+ int ret;
+
+ // create a copy of the RRSet
+ /*! \todo If the packet was not parsed all at once, we could save this
+ * copy.
+ */
+ knot_rrset_t *rrset_copy;
+ ret = knot_rrset_deep_copy(rrset, &rrset_copy);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /*! \todo What about the SOAs? */
+
+ if (knot_rrset_class(rrset) == qclass) {
+ // this RRSet should be added to the zone
+ ret = knot_changeset_add_rr(&changeset->add,
+ &changeset->add_count,
+ &changeset->add_allocated,
+ rrset_copy);
+ } else {
+ // this RRSet marks removal of something from zone
+ // what should be removed is distinguished when applying
+ ret = knot_changeset_add_rr(&changeset->remove,
+ &changeset->remove_count,
+ &changeset->remove_allocated,
+ rrset_copy);
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_check_exist(const knot_zone_contents_t *zone,
+ const knot_rrset_t *rrset, uint8_t *rcode)
+{
+ assert(zone != NULL);
+ assert(rrset != NULL);
+ assert(rcode != NULL);
+ assert(knot_rrset_rdata(rrset) == NULL);
+ assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY);
+ assert(knot_rrset_ttl(rrset) == 0);
+ assert(knot_rrset_class(rrset) == KNOT_CLASS_ANY);
+
+ if (!knot_dname_is_subdomain(knot_rrset_owner(rrset),
+ knot_node_owner(knot_zone_contents_apex(zone)))) {
+ *rcode = KNOT_RCODE_NOTZONE;
+ return KNOT_EBADZONE;
+ }
+
+ const knot_node_t *node;
+ node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset));
+ if (node == NULL) {
+ *rcode = KNOT_RCODE_NXRRSET;
+ return KNOT_ENONODE;
+ } else if (knot_node_rrset(node, knot_rrset_type(rrset)) == NULL) {
+ *rcode = KNOT_RCODE_NXRRSET;
+ return KNOT_ENORRSET;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone,
+ const knot_rrset_t *rrset, uint8_t *rcode)
+{
+ assert(zone != NULL);
+ assert(rrset != NULL);
+ assert(rcode != NULL);
+ assert(knot_rrset_rdata(rrset) == NULL);
+ assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY);
+ assert(knot_rrset_ttl(rrset) == 0);
+ assert(knot_rrset_class(rrset) == KNOT_CLASS_ANY);
+
+ if (!knot_dname_is_subdomain(knot_rrset_owner(rrset),
+ knot_node_owner(knot_zone_contents_apex(zone)))) {
+ *rcode = KNOT_RCODE_NOTZONE;
+ return KNOT_EBADZONE;
+ }
+
+ const knot_node_t *node;
+ const knot_rrset_t *found;
+
+ node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset));
+ if (node == NULL) {
+ *rcode = KNOT_RCODE_NXRRSET;
+ return KNOT_EPREREQ;
+ } else if ((found = knot_node_rrset(node, knot_rrset_type(rrset)))
+ == NULL) {
+ *rcode = KNOT_RCODE_NXRRSET;
+ return KNOT_EPREREQ;
+ } else {
+ // do not have to compare the header, it is already done
+ assert(knot_rrset_type(found) == knot_rrset_type(rrset));
+ assert(knot_dname_compare(knot_rrset_owner(found),
+ knot_rrset_owner(rrset)) == 0);
+ if (knot_rrset_compare_rdata(found, rrset) <= 0) {
+ *rcode = KNOT_RCODE_NXRRSET;
+ return KNOT_EPREREQ;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone,
+ const knot_rrset_t *rrset, uint8_t *rcode)
+{
+ assert(zone != NULL);
+ assert(rrset != NULL);
+ assert(rcode != NULL);
+ assert(knot_rrset_rdata(rrset) == NULL);
+ assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY);
+ assert(knot_rrset_ttl(rrset) == 0);
+ assert(knot_rrset_class(rrset) == KNOT_CLASS_NONE);
+
+ if (!knot_dname_is_subdomain(knot_rrset_owner(rrset),
+ knot_node_owner(knot_zone_contents_apex(zone)))) {
+ *rcode = KNOT_RCODE_NOTZONE;
+ return KNOT_EBADZONE;
+ }
+
+ const knot_node_t *node;
+ const knot_rrset_t *found;
+
+ node = knot_zone_contents_find_node(zone, knot_rrset_owner(rrset));
+ if (node == NULL) {
+ return KNOT_EOK;
+ } else if ((found = knot_node_rrset(node, knot_rrset_type(rrset)))
+ == NULL) {
+ return KNOT_EOK;
+ } else {
+ // do not have to compare the header, it is already done
+ assert(knot_rrset_type(found) == knot_rrset_type(rrset));
+ assert(knot_dname_compare(knot_rrset_owner(found),
+ knot_rrset_owner(rrset)) == 0);
+ if (knot_rrset_compare_rdata(found, rrset) <= 0) {
+ return KNOT_EOK;
+ }
+ }
+
+ *rcode = KNOT_RCODE_YXRRSET;
+ return KNOT_EPREREQ;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_check_in_use(const knot_zone_contents_t *zone,
+ const knot_dname_t *dname, uint8_t *rcode)
+{
+ assert(zone != NULL);
+ assert(dname != NULL);
+ assert(rcode != NULL);
+
+ if (!knot_dname_is_subdomain(dname,
+ knot_node_owner(knot_zone_contents_apex(zone)))) {
+ *rcode = KNOT_RCODE_NOTZONE;
+ return KNOT_EBADZONE;
+ }
+
+ const knot_node_t *node;
+
+ node = knot_zone_contents_find_node(zone, dname);
+ if (node == NULL) {
+ *rcode = KNOT_RCODE_NXDOMAIN;
+ return KNOT_EPREREQ;
+ } else if (knot_node_rrset_count(node) == 0) {
+ *rcode = KNOT_RCODE_NXDOMAIN;
+ return KNOT_EPREREQ;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_check_not_in_use(const knot_zone_contents_t *zone,
+ const knot_dname_t *dname, uint8_t *rcode)
+{
+ assert(zone != NULL);
+ assert(dname != NULL);
+ assert(rcode != NULL);
+
+ if (!knot_dname_is_subdomain(dname,
+ knot_node_owner(knot_zone_contents_apex(zone)))) {
+ *rcode = KNOT_RCODE_NOTZONE;
+ return KNOT_EBADZONE;
+ }
+
+ const knot_node_t *node;
+
+ node = knot_zone_contents_find_node(zone, dname);
+ if (node == NULL) {
+ return KNOT_EOK;
+ } else if (knot_node_rrset_count(node) == 0) {
+ return KNOT_EOK;
+ }
+
+ *rcode = KNOT_RCODE_YXDOMAIN;
+ return KNOT_EPREREQ;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+int knot_ddns_check_zone(const knot_zone_t *zone, knot_packet_t *query,
+ uint8_t *rcode)
+{
+ if (zone == NULL || query == NULL || rcode == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ if (knot_packet_qtype(query) != KNOT_RRTYPE_SOA) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+
+ if(!knot_zone_contents(zone)) {
+ *rcode = KNOT_RCODE_REFUSED;
+ return KNOT_ENOZONE;
+ }
+
+ // 1) check if the zone is master or slave
+ if (!knot_zone_is_master(zone)) {
+ return KNOT_EBADZONE;
+ }
+
+ // 2) check zone CLASS
+ if (knot_zone_contents_class(knot_zone_contents(zone)) !=
+ knot_packet_qclass(query)) {
+ *rcode = KNOT_RCODE_NOTAUTH;
+ return KNOT_ENOZONE;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ddns_process_prereqs(knot_packet_t *query,
+ knot_ddns_prereq_t **prereqs, uint8_t *rcode)
+{
+ /*! \todo Consider not parsing the whole packet at once, but
+ * parsing one RR at a time - could save some memory and time.
+ */
+
+ if (query == NULL || prereqs == NULL || rcode == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // allocate space for the prerequisities
+ *prereqs = (knot_ddns_prereq_t *)calloc(1, sizeof(knot_ddns_prereq_t));
+ CHECK_ALLOC_LOG(*prereqs, KNOT_ENOMEM);
+
+ int ret;
+
+ for (int i = 0; i < knot_packet_answer_rrset_count(query); ++i) {
+ // we must copy the RRSets, because all those stored in the
+ // packet will be destroyed
+ ret = knot_ddns_add_prereq(*prereqs,
+ knot_packet_answer_rrset(query, i),
+ knot_packet_qclass(query));
+ if (ret != KNOT_EOK) {
+ dbg_ddns("Failed to add prerequisity RRSet:%s\n",
+ knot_strerror(ret));
+ *rcode = (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR
+ : KNOT_RCODE_SERVFAIL;
+ knot_ddns_prereqs_free(prereqs);
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ddns_check_prereqs(const knot_zone_contents_t *zone,
+ knot_ddns_prereq_t **prereqs, uint8_t *rcode)
+{
+ int i, ret;
+
+ for (i = 0; i < (*prereqs)->exist_count; ++i) {
+ ret = knot_ddns_check_exist(zone, (*prereqs)->exist[i], rcode);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ for (i = 0; i < (*prereqs)->exist_full_count; ++i) {
+ ret = knot_ddns_check_exist_full(zone,
+ (*prereqs)->exist_full[i],
+ rcode);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ for (i = 0; i < (*prereqs)->not_exist_count; ++i) {
+ ret = knot_ddns_check_not_exist(zone, (*prereqs)->not_exist[i],
+ rcode);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ for (i = 0; i < (*prereqs)->in_use_count; ++i) {
+ ret = knot_ddns_check_in_use(zone, (*prereqs)->in_use[i],
+ rcode);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ for (i = 0; i < (*prereqs)->not_in_use_count; ++i) {
+ ret = knot_ddns_check_not_in_use(zone,
+ (*prereqs)->not_in_use[i],
+ rcode);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_ddns_check_update(const knot_rrset_t *rrset,
+ const knot_packet_t *query, uint8_t *rcode)
+{
+ if (!knot_dname_is_subdomain(knot_rrset_owner(rrset),
+ knot_packet_qname(query))) {
+ *rcode = KNOT_RCODE_NOTZONE;
+ return KNOT_EBADZONE;
+ }
+
+ if (knot_rrset_class(rrset) == knot_packet_qclass(query)) {
+ if (knot_rrtype_is_metatype(knot_rrset_type(rrset))) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+ } else if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) {
+ if (knot_rrset_rdata(rrset) != NULL
+ || (knot_rrtype_is_metatype(knot_rrset_type(rrset))
+ && knot_rrset_type(rrset) != KNOT_RRTYPE_ANY)) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+ } else if (knot_rrset_class(rrset) == KNOT_CLASS_NONE) {
+ if (knot_rrset_ttl(rrset) != 0
+ || knot_rrtype_is_metatype(knot_rrset_type(rrset))) {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+ } else {
+ *rcode = KNOT_RCODE_FORMERR;
+ return KNOT_EMALF;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_ddns_process_update(knot_packet_t *query,
+ knot_changeset_t **changeset, uint8_t *rcode)
+{
+ // just put all RRSets from query's Authority section
+ // it will be distinguished when applying to the zone
+
+ if (query == NULL || changeset == NULL || rcode == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ *changeset = (knot_changeset_t *)calloc(1, sizeof(knot_changeset_t));
+ CHECK_ALLOC_LOG(*changeset, KNOT_ENOMEM);
+
+ int ret;
+
+ for (int i = 0; i < knot_packet_authority_rrset_count(query); ++i) {
+
+ const knot_rrset_t *rrset =
+ knot_packet_authority_rrset(query, i);
+
+ ret = knot_ddns_check_update(rrset, query, rcode);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = knot_ddns_add_update(*changeset, rrset,
+ knot_packet_qclass(query));
+
+ if (ret != KNOT_EOK) {
+ dbg_ddns("Failed to add update RRSet:%s\n",
+ knot_strerror(ret));
+ *rcode = (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR
+ : KNOT_RCODE_SERVFAIL;
+ knot_free_changeset(changeset);
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq)
+{
+ int i;
+
+ for (i = 0; i < (*prereq)->exist_count; ++i) {
+ knot_rrset_deep_free(&(*prereq)->exist[i], 1, 1, 1);
+ }
+
+ for (i = 0; i < (*prereq)->exist_full_count; ++i) {
+ knot_rrset_deep_free(&(*prereq)->exist_full[i], 1, 1, 1);
+ }
+
+ for (i = 0; i < (*prereq)->not_exist_count; ++i) {
+ knot_rrset_deep_free(&(*prereq)->not_exist[i], 1, 1, 1);
+ }
+
+ for (i = 0; i < (*prereq)->in_use_count; ++i) {
+ knot_dname_free(&(*prereq)->in_use[i]);
+ }
+
+ for (i = 0; i < (*prereq)->not_in_use_count; ++i) {
+ knot_dname_free(&(*prereq)->not_in_use[i]);
+ }
+
+ free(*prereq);
+ *prereq = NULL;
+}
diff --git a/src/libknot/updates/ddns.h b/src/libknot/updates/ddns.h
new file mode 100644
index 0000000..dceebed
--- /dev/null
+++ b/src/libknot/updates/ddns.h
@@ -0,0 +1,74 @@
+/*!
+ * \file ddns.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Dynamic updates processing.
+ *
+ * \addtogroup query_processing
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_DDNS_H_
+#define _KNOT_DDNS_H_
+
+#include "updates/changesets.h"
+#include "zone/zone.h"
+#include "packet/packet.h"
+#include "rrset.h"
+#include "dname.h"
+
+typedef struct knot_ddns_prereq_t {
+ knot_rrset_t **exist;
+ size_t exist_count;
+ size_t exist_allocd;
+
+ knot_rrset_t **exist_full;
+ size_t exist_full_count;
+ size_t exist_full_allocd;
+
+ knot_rrset_t **not_exist;
+ size_t not_exist_count;
+ size_t not_exist_allocd;
+
+ knot_dname_t **in_use;
+ size_t in_use_count;
+ size_t in_use_allocd;
+
+ knot_dname_t **not_in_use;
+ size_t not_in_use_count;
+ size_t not_in_use_allocd;
+} knot_ddns_prereq_t;
+
+int knot_ddns_check_zone(const knot_zone_t *zone, knot_packet_t *query,
+ uint8_t *rcode);
+
+int knot_ddns_process_prereqs(knot_packet_t *query,
+ knot_ddns_prereq_t **prereqs, uint8_t *rcode);
+
+int knot_ddns_check_prereqs(const knot_zone_contents_t *zone,
+ knot_ddns_prereq_t **prereqs, uint8_t *rcode);
+
+int knot_ddns_process_update(knot_packet_t *query,
+ knot_changeset_t **changeset, uint8_t *rcode);
+
+void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq);
+
+#endif /* _KNOT_DDNS_H_ */
+
+/*! @} */
diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c
new file mode 100644
index 0000000..51be430
--- /dev/null
+++ b/src/libknot/updates/xfr-in.c
@@ -0,0 +1,3013 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <urcu.h>
+
+#include "updates/xfr-in.h"
+
+#include "nameserver/name-server.h"
+#include "util/wire.h"
+#include "util/debug.h"
+// #include "knot/zone/zone-dump.h"
+// #include "knot/zone/zone-load.h"
+#include "packet/packet.h"
+#include "dname.h"
+#include "zone/zone.h"
+#include "packet/query.h"
+#include "packet/response.h"
+#include "util/error.h"
+#include "updates/changesets.h"
+#include "tsig.h"
+#include "tsig-op.h"
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype,
+ uint16_t qclass, knot_ns_xfr_t *xfr, size_t *size,
+ const knot_rrset_t *soa, int use_tsig)
+{
+ knot_packet_t *pkt = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ CHECK_ALLOC_LOG(pkt, KNOT_ENOMEM);
+
+ /*! \todo Get rid of the numeric constant. */
+ int rc = knot_packet_set_max_size(pkt, 512);
+ if (rc != KNOT_EOK) {
+ knot_packet_free(&pkt);
+ return KNOT_ERROR;
+ }
+
+ rc = knot_query_init(pkt);
+ if (rc != KNOT_EOK) {
+ knot_packet_free(&pkt);
+ return KNOT_ERROR;
+ }
+
+ knot_question_t question;
+
+ /* Retain qname until the question is freed. */
+ knot_dname_retain(qname);
+
+ /* Set random query ID. */
+ knot_packet_set_random_id(pkt);
+ knot_wire_set_id(pkt->wireformat, pkt->header.id);
+
+ // this is ugly!!
+ question.qname = (knot_dname_t *)qname;
+ question.qtype = qtype;
+ question.qclass = qclass;
+
+ rc = knot_query_set_question(pkt, &question);
+ if (rc != KNOT_EOK) {
+ knot_dname_release(question.qname);
+ knot_packet_free(&pkt);
+ return KNOT_ERROR;
+ }
+
+ /* Reserve space for TSIG. */
+ if (use_tsig && xfr->tsig_key) {
+ dbg_xfrin_detail("xfrin: setting packet TSIG size to %zu\n",
+ xfr->tsig_size);
+ knot_packet_set_tsig_size(pkt, xfr->tsig_size);
+ }
+
+ /* Add SOA RR to authority section for IXFR. */
+ if (qtype == KNOT_RRTYPE_IXFR && soa) {
+ knot_query_add_rrset_authority(pkt, soa);
+ }
+
+ /*! \todo OPT RR ?? */
+
+ uint8_t *wire = NULL;
+ size_t wire_size = 0;
+ rc = knot_packet_to_wire(pkt, &wire, &wire_size);
+ if (rc != KNOT_EOK) {
+ dbg_xfrin("Failed to write packet to wire.\n");
+ knot_dname_release(question.qname);
+ knot_packet_free(&pkt);
+ return KNOT_ERROR;
+ }
+
+ if (wire_size > *size) {
+ dbg_xfrin("Not enough space provided for the wire "
+ "format of the query.\n");
+ knot_packet_free(&pkt);
+ return KNOT_ESPACE;
+ }
+
+ // wire format created, sign it with TSIG if required
+ if (use_tsig && xfr->tsig_key) {
+ char *name = knot_dname_to_str(xfr->tsig_key->name);
+ dbg_xfrin_detail("Signing XFR query with key (name %s): \n",
+ name);
+ free(name);
+ dbg_xfrin_hex_detail(xfr->tsig_key->secret,
+ xfr->tsig_key->secret_size);
+
+ xfr->digest_size = xfr->digest_max_size;
+ rc = knot_tsig_sign(wire, &wire_size, *size, NULL, 0,
+ xfr->digest, &xfr->digest_size, xfr->tsig_key);
+ if (rc != KNOT_EOK) {
+ /*! \todo [TSIG] Handle TSIG errors. */
+ knot_packet_free(&pkt);
+ return rc;
+ }
+
+ dbg_xfrin_detail("Signed XFR query, new wire size: %zu, digest:"
+ "\n", wire_size);
+ dbg_xfrin_hex_detail((const char*)xfr->digest, xfr->digest_size);
+ }
+
+ memcpy(xfr->wire, wire, wire_size);
+ *size = wire_size;
+
+ dbg_xfrin("Created query of size %zu.\n", *size);
+ knot_packet_dump(pkt);
+
+ knot_packet_free(&pkt);
+
+ /* Release qname. */
+ knot_dname_release(question.qname);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+int xfrin_create_soa_query(knot_dname_t *owner, knot_ns_xfr_t *xfr,
+ size_t *size)
+{
+ /*! \todo [TSIG] Should TSIG apply for SOA query too? */
+ return xfrin_create_query(owner, KNOT_RRTYPE_SOA,
+ KNOT_CLASS_IN, xfr, size, 0, 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int xfrin_transfer_needed(const knot_zone_contents_t *zone,
+ knot_packet_t *soa_response)
+{
+ // first, parse the rest of the packet
+ assert(!knot_packet_is_query(soa_response));
+ dbg_xfrin("Response - parsed: %zu, total wire size: %zu\n",
+ soa_response->parsed, soa_response->size);
+ int ret;
+
+ if (soa_response->parsed < soa_response->size) {
+ ret = knot_packet_parse_rest(soa_response);
+ if (ret != KNOT_EOK) {
+ return KNOT_EMALF;
+ }
+ }
+
+ /*
+ * Retrieve the local Serial
+ */
+ const knot_rrset_t *soa_rrset =
+ knot_node_rrset(knot_zone_contents_apex(zone),
+ KNOT_RRTYPE_SOA);
+ if (soa_rrset == NULL) {
+ char *name = knot_dname_to_str(knot_node_owner(
+ knot_zone_contents_apex(zone)));
+ dbg_xfrin("SOA RRSet missing in the zone %s!\n", name);
+ free(name);
+ return KNOT_ERROR;
+ }
+
+ int64_t local_serial = knot_rdata_soa_serial(
+ knot_rrset_rdata(soa_rrset));
+ if (local_serial < 0) {
+dbg_xfrin_exec(
+ char *name = knot_dname_to_str(knot_rrset_owner(soa_rrset));
+ dbg_xfrin("Malformed data in SOA of zone %s\n", name);
+ free(name);
+);
+ return KNOT_EMALF; // maybe some other error
+ }
+
+ /*
+ * Retrieve the remote Serial
+ */
+ // the SOA should be the first (and only) RRSet in the response
+ soa_rrset = knot_packet_answer_rrset(soa_response, 0);
+ if (soa_rrset == NULL
+ || knot_rrset_type(soa_rrset) != KNOT_RRTYPE_SOA) {
+ return KNOT_EMALF;
+ }
+
+ int64_t remote_serial = knot_rdata_soa_serial(
+ knot_rrset_rdata(soa_rrset));
+ if (remote_serial < 0) {
+ return KNOT_EMALF; // maybe some other error
+ }
+
+ return (ns_serial_compare(local_serial, remote_serial) < 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int xfrin_create_axfr_query(knot_dname_t *owner, knot_ns_xfr_t *xfr,
+ size_t *size, int use_tsig)
+{
+ return xfrin_create_query(owner, KNOT_RRTYPE_AXFR,
+ KNOT_CLASS_IN, xfr, size, 0, use_tsig);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int xfrin_create_ixfr_query(const knot_zone_contents_t *zone,
+ knot_ns_xfr_t *xfr, size_t *size, int use_tsig)
+{
+ /*!
+ * \todo Implement properly.
+ */
+ knot_node_t *apex = knot_zone_contents_get_apex(zone);
+ const knot_rrset_t *soa = knot_node_rrset(apex, KNOT_RRTYPE_SOA);
+
+ return xfrin_create_query(knot_node_get_owner(apex), KNOT_RRTYPE_IXFR,
+ KNOT_CLASS_IN, xfr, size, soa, use_tsig);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_add_orphan_rrsig(xfrin_orphan_rrsig_t *rrsigs,
+ knot_rrset_t *rr)
+{
+ // try to find similar RRSIGs (check owner and type covered) in the list
+ assert(knot_rrset_type(rr) == KNOT_RRTYPE_RRSIG);
+
+ int ret = 0;
+ xfrin_orphan_rrsig_t **last = &rrsigs;
+ while (*last != NULL) {
+ // check if the RRSIG is not similar to the one we want to add
+ assert((*last)->rrsig != NULL);
+ if (knot_rrset_compare((*last)->rrsig, rr,
+ KNOT_RRSET_COMPARE_HEADER) == 1
+ && knot_rdata_rrsig_type_covered(knot_rrset_rdata(
+ (*last)->rrsig))
+ == knot_rdata_rrsig_type_covered(knot_rrset_rdata(rr))) {
+ ret = knot_rrset_merge((void **)&(*last)->rrsig,
+ (void **)&rr);
+ if (ret != KNOT_EOK) {
+ return ret;
+ } else {
+ return 1;
+ }
+ }
+ last = &((*last)->next);
+ }
+
+ assert(*last == NULL);
+ // we did not find the right RRSIGs, add to the end
+ *last = (xfrin_orphan_rrsig_t *)malloc(sizeof(xfrin_orphan_rrsig_t));
+ CHECK_ALLOC_LOG(*last, KNOT_ENOMEM);
+
+ (*last)->rrsig = rr;
+ (*last)->next = NULL;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_process_orphan_rrsigs(knot_zone_contents_t *zone,
+ xfrin_orphan_rrsig_t *rrsigs)
+{
+ xfrin_orphan_rrsig_t **last = &rrsigs;
+ int ret = 0;
+ while (*last != NULL) {
+ knot_rrset_t *rrset = NULL;
+ knot_node_t *node = NULL;
+ ret = knot_zone_contents_add_rrsigs(zone, (*last)->rrsig,
+ &rrset, &node,
+ KNOT_RRSET_DUPL_MERGE, 1);
+ if (ret > 0) {
+ knot_rrset_free(&(*last)->rrsig);
+ } else if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add orphan RRSIG to zone.\n");
+ return ret;
+ } else {
+ (*last)->rrsig = NULL;
+ }
+
+ last = &((*last)->next);
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_free_orphan_rrsigs(xfrin_orphan_rrsig_t **rrsigs)
+{
+ xfrin_orphan_rrsig_t *r = *rrsigs;
+ while (r != NULL) {
+ xfrin_orphan_rrsig_t *prev = r;
+ r = r->next;
+ free(prev);
+ }
+
+ *rrsigs = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+/*! \note [TSIG] */
+static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr,
+ int tsig_req)
+{
+ assert(packet != NULL);
+ assert(xfr != NULL);
+
+ dbg_xfrin_verb("xfrin_check_tsig(): packet nr: %d, required: %d\n",
+ xfr->packet_nr, tsig_req);
+
+ /*
+ * If we are expecting it (i.e. xfr->prev_digest_size > 0)
+ * a) it should be there (first, last or each 100th packet) and it
+ * is not
+ * Then we should discard the changes and close the connection.
+ * b) it should be there and it is or it may not be there (other
+ * packets) and it is
+ * We validate the TSIG and reset packet number counting and
+ * data aggregation.
+ *
+ * If we are not expecting it (i.e. xfr->prev_digest_size <= 0) and
+ * it is there => it should probably be considered an error
+ */
+ knot_rrset_t *tsig = NULL;
+ int ret = knot_packet_parse_next_rr_additional(packet, &tsig);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ if (xfr->tsig_key) {
+ if (tsig_req && tsig == NULL) {
+ // TSIG missing!!
+ return KNOT_EMALF;
+ } else if (tsig != NULL) {
+ // TSIG there, either required or not, process
+ if (xfr->packet_nr == 0) {
+ ret = knot_tsig_client_check(tsig,
+ xfr->wire, xfr->wire_size,
+ xfr->digest, xfr->digest_size,
+ xfr->tsig_key);
+ } else {
+ ret = knot_tsig_client_check_next(tsig,
+ xfr->wire, xfr->wire_size,
+ xfr->digest, xfr->digest_size,
+ xfr->tsig_key);
+ }
+
+ if (ret != KNOT_EOK) {
+ /*! \note [TSIG] No need to check TSIG error
+ * here, propagate and check elsewhere.*/
+ return ret;
+ }
+
+ // and reset the data storage
+ //xfr->packet_nr = 1;
+ xfr->tsig_data_size = 0;
+
+ // Extract the digest from the TSIG RDATA and store it.
+ if (xfr->digest_max_size < tsig_rdata_mac_length(tsig)) {
+ return KNOT_ESPACE;
+ }
+ memcpy(xfr->digest, tsig_rdata_mac(tsig),
+ tsig_rdata_mac_length(tsig));
+ xfr->digest_size = tsig_rdata_mac_length(tsig);
+
+ } else { // TSIG not required and not there
+ // just append the wireformat to the TSIG data
+ assert(KNOT_NS_TSIG_DATA_MAX_SIZE - xfr->tsig_data_size
+ >= xfr->wire_size);
+ memcpy(xfr->tsig_data + xfr->tsig_data_size,
+ xfr->wire, xfr->wire_size);
+ xfr->tsig_data_size += xfr->wire_size;
+ }
+ } else if (tsig != NULL) {
+ // TSIG where it should not be
+ return KNOT_EMALF;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size,
+ xfrin_constructed_zone_t **constr*/
+ knot_ns_xfr_t *xfr)
+{
+ const uint8_t *pkt = xfr->wire;
+ size_t size = xfr->wire_size;
+ xfrin_constructed_zone_t **constr =
+ (xfrin_constructed_zone_t **)(&xfr->data);
+
+ if (pkt == NULL || constr == NULL) {
+ dbg_xfrin("Wrong parameters supported.\n");
+ return KNOT_EBADARG;
+ }
+
+ dbg_xfrin("Processing AXFR packet of size %zu.\n", size);
+
+ // check if the response is OK
+ if (knot_wire_get_rcode(pkt) != KNOT_RCODE_NOERROR) {
+ return KNOT_EXFRREFUSED;
+ }
+
+ /*! \todo Should TC bit be checked? */
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ if (packet == NULL) {
+ dbg_xfrin("Could not create packet structure.\n");
+ return KNOT_ENOMEM;
+ }
+
+ int ret = knot_packet_parse_from_wire(packet, pkt, size, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Could not parse packet: %s.\n",
+ knot_strerror(ret));
+ knot_packet_free(&packet);
+ /*! \todo Cleanup. */
+ return KNOT_EMALF;
+ }
+
+ /*! \todo [TSIG] If packet RCODE is NOTAUTH(9), process as TSIG error. */
+
+ knot_rrset_t *rr = NULL;
+ ret = knot_packet_parse_next_rr_answer(packet, &rr);
+
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Could not parse first Answer RR: %s.\n",
+ knot_strerror(ret));
+ knot_packet_free(&packet);
+ /*! \todo Cleanup. */
+ return KNOT_EMALF;
+ }
+
+ if (rr == NULL) {
+ dbg_xfrin("No RRs in the packet.\n");
+ knot_packet_free(&packet);
+ /*! \todo Cleanup. */
+ return KNOT_EMALF;
+ }
+
+ /*! \todo We should probably test whether the Question of the first
+ * message corresponds to the SOA RR.
+ */
+
+ knot_node_t *node = NULL;
+ int in_zone = 0;
+ knot_zone_contents_t *zone = NULL;
+
+ if (*constr == NULL) {
+ // this should be the first packet
+ /*! \note [TSIG] Packet number for checking TSIG validation. */
+ xfr->packet_nr = 0;
+ /*! \note [TSIG] Storing total size of data for TSIG digest. */
+ xfr->tsig_data_size = 0;
+
+ // create new zone
+ /*! \todo Ensure that the packet is the first one. */
+ if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) {
+ dbg_xfrin("No zone created, but the first RR in "
+ "Answer is not a SOA RR.\n");
+ knot_packet_free(&packet);
+ knot_node_free(&node, 0, 0);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ /*! \todo Cleanup. */
+ return KNOT_EMALF;
+ }
+
+ if (knot_dname_compare(knot_rrset_owner(rr),
+ knot_packet_qname(packet)) != 0) {
+dbg_xfrin_exec(
+ char *rr_owner =
+ knot_dname_to_str(knot_rrset_owner(rr));
+ char *qname = knot_dname_to_str(
+ knot_packet_qname(packet));
+
+ dbg_xfrin("Owner of the first SOA RR (%s) does not"
+ " match QNAME (%s).\n", rr_owner, qname);
+
+ free(rr_owner);
+ free(qname);
+);
+ /*! \todo Cleanup. */
+ knot_packet_free(&packet);
+ knot_node_free(&node, 0, 0);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return KNOT_EMALF;
+ }
+
+ node = knot_node_new(rr->owner, NULL, 0);
+ if (node == NULL) {
+ dbg_xfrin("Failed to create new node.\n");
+ knot_packet_free(&packet);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return KNOT_ENOMEM;
+ }
+
+ // the first RR is SOA and its owner and QNAME are the same
+ // create the zone
+
+ *constr = (xfrin_constructed_zone_t *)malloc(
+ sizeof(xfrin_constructed_zone_t));
+ if (*constr == NULL) {
+ dbg_xfrin("Failed to create new constr. zone.\n");
+ knot_packet_free(&packet);
+ knot_node_free(&node, 0, 0);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return KNOT_ENOMEM;
+ }
+
+ memset(*constr, 0, sizeof(xfrin_constructed_zone_t));
+
+ (*constr)->contents = knot_zone_contents_new(node, 0, 1, NULL);
+// assert(0);
+ if ((*constr)->contents== NULL) {
+ dbg_xfrin("Failed to create new zone.\n");
+ knot_packet_free(&packet);
+ knot_node_free(&node, 0, 0);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ /*! \todo Cleanup. */
+ return KNOT_ENOMEM;
+ }
+
+ in_zone = 1;
+ assert(node->owner == rr->owner);
+ zone = (*constr)->contents;
+ assert(zone->apex == node);
+ assert(zone->apex->owner == rr->owner);
+ // add the RRSet to the node
+ //ret = knot_node_add_rrset(node, rr, 0);
+ ret = knot_zone_contents_add_rrset(zone, rr, &node,
+ KNOT_RRSET_DUPL_MERGE, 1);
+ if (ret < 0) {
+ dbg_xfrin("Failed to add RRSet to zone node: %s.\n",
+ knot_strerror(ret));
+ knot_packet_free(&packet);
+ knot_node_free(&node, 0, 0);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ /*! \todo Cleanup. */
+ return KNOT_ERROR;
+ } else if (ret > 0) {
+ dbg_xfrin("Merged SOA RRSet.\n");
+ // merged, free the RRSet
+ //knot_rrset_deep_free(&rr, 1, 0, 0);
+ knot_rrset_free(&rr);
+ }
+
+ // take next RR
+ ret = knot_packet_parse_next_rr_answer(packet, &rr);
+ } else {
+ zone = (*constr)->contents;
+ ++xfr->packet_nr;
+ }
+
+ /*! \note [TSIG] add the packet wire size to the data to be verified by
+ * TSIG
+ */
+ if (xfr->tsig_key) {
+ dbg_xfrin("Adding packet wire to TSIG data (size till now: %zu,"
+ " adding: %zu).\n", xfr->tsig_data_size,
+ xfr->wire_size);
+ assert(KNOT_NS_TSIG_DATA_MAX_SIZE - xfr->tsig_data_size
+ >= xfr->wire_size);
+ memcpy(xfr->tsig_data + xfr->tsig_data_size, xfr->wire,
+ xfr->wire_size);
+ xfr->tsig_data_size += xfr->wire_size;
+ }
+
+ assert(zone != NULL);
+
+ while (ret == KNOT_EOK && rr != NULL) {
+ // process the parsed RR
+
+ dbg_xfrin("\nNext RR:\n\n");
+ knot_rrset_dump(rr, 0);
+
+ if (node != NULL
+ && knot_dname_compare(rr->owner, node->owner) != 0) {
+dbg_xfrin_exec(
+ char *name = knot_dname_to_str(node->owner);
+ dbg_xfrin("Node owner: %s\n", name);
+ free(name);
+);
+ if (!in_zone) {
+ // this should not happen
+ assert(0);
+ // the node is not in the zone and the RR has
+ // other owner, so a new node must be created
+ // insert the old node to the zone
+ }
+
+ node = NULL;
+ }
+
+ if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) {
+ // this must be the last SOA, do not do anything more
+ // discard the RR
+ assert(knot_zone_contents_apex((zone)) != NULL);
+ assert(knot_node_rrset(knot_zone_contents_apex((zone)),
+ KNOT_RRTYPE_SOA) != NULL);
+ dbg_xfrin("Found last SOA, transfer finished.\n");
+
+ dbg_xfrin("Verifying TSIG...\n");
+ /*! \note [TSIG] Now check if there is not a TSIG record
+ * at the end of the packet.
+ */
+ ret = xfrin_check_tsig(packet, xfr, 1);
+
+ dbg_xfrin_detail("xfrin_check_tsig() returned %d\n",
+ ret);
+
+ knot_packet_free(&packet);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+
+ if (ret != KNOT_EOK) {
+ /*! \todo [TSIG] Handle TSIG errors. */
+ return ret;
+ }
+
+ // we must now find place for all orphan RRSIGs
+ ret = xfrin_process_orphan_rrsigs(zone,
+ (*constr)->rrsigs);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to process orphan "
+ "RRSIGs\n");
+ /*! \todo Cleanup?? */
+ return ret;
+ }
+
+ xfrin_free_orphan_rrsigs(&(*constr)->rrsigs);
+
+ return 1;
+ }
+
+ if (knot_rrset_type(rr) == KNOT_RRTYPE_RRSIG) {
+ // RRSIGs require special handling, as there are no
+ // nodes for them
+ knot_rrset_t *tmp_rrset = NULL;
+ ret = knot_zone_contents_add_rrsigs(zone, rr,
+ &tmp_rrset, &node, KNOT_RRSET_DUPL_MERGE, 1);
+ if (ret == KNOT_ENONODE || ret == KNOT_ENORRSET) {
+ dbg_xfrin("No node or RRSet for RRSIGs\n");
+ dbg_xfrin("Saving for later insertion.\n");
+ ret = xfrin_add_orphan_rrsig((*constr)->rrsigs,
+ rr);
+ if (ret > 0) {
+ dbg_xfrin("Merged RRSIGs.\n");
+ knot_rrset_free(&rr);
+ } else if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to save orphan"
+ " RRSIGs.\n");
+ knot_packet_free(&packet);
+ knot_node_free(&node, 1, 0); // ???
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return ret;
+ }
+ } else if (ret < 0) {
+ dbg_xfrin("Failed to add RRSIGs (%s).\n",
+ knot_strerror(ret));
+ knot_packet_free(&packet);
+ knot_node_free(&node, 1, 0); // ???
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return KNOT_ERROR; /*! \todo Other error code. */
+ } else if (ret == 1) {
+ assert(node != NULL);
+dbg_xfrin_exec(
+ char *name = knot_dname_to_str(node->owner);
+ dbg_xfrin("Found node for the record in "
+ "zone: %s.\n", name);
+ free(name);
+);
+ in_zone = 1;
+ knot_rrset_deep_free(&rr, 1, 0, 0);
+ } else if (ret == 2) {
+ // should not happen
+ assert(0);
+// knot_rrset_deep_free(&rr, 1, 1, 1);
+ } else {
+ assert(node != NULL);
+dbg_xfrin_exec(
+ char *name = knot_dname_to_str(node->owner);
+ dbg_xfrin("Found node for the record in "
+ "zone: %s.\n", name);
+ free(name);
+);
+ in_zone = 1;
+ assert(tmp_rrset->rrsigs == rr);
+ }
+
+ // parse next RR
+ ret = knot_packet_parse_next_rr_answer(packet, &rr);
+
+ continue;
+ }
+
+ /*! \note [TSIG] TSIG where it should not be - in Answer section.*/
+ if (knot_rrset_type(rr) == KNOT_RRTYPE_TSIG) {
+ // not allowed here
+ dbg_xfrin(" in Answer section.\n");
+ knot_packet_free(&packet);
+ knot_node_free(&node, 1, 0); // ???
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return KNOT_EMALF;
+ }
+
+ knot_node_t *(*get_node)(const knot_zone_contents_t *,
+ const knot_dname_t *) = NULL;
+ int (*add_node)(knot_zone_contents_t *, knot_node_t *, int,
+ uint8_t, int) = NULL;
+
+ if (knot_rrset_type(rr) == KNOT_RRTYPE_NSEC3) {
+ get_node = knot_zone_contents_get_nsec3_node;
+ add_node = knot_zone_contents_add_nsec3_node;
+ } else {
+ get_node = knot_zone_contents_get_node;
+ add_node = knot_zone_contents_add_node;
+ }
+
+ if (node == NULL && (node = get_node(zone,
+ knot_rrset_owner(rr))) != NULL) {
+ // the node for this RR was found in the zone
+ dbg_xfrin("Found node for the record in zone.\n");
+ in_zone = 1;
+ }
+
+ if (node == NULL) {
+ // a new node for the RR is required but it is not
+ // in the zone
+ node = knot_node_new(rr->owner, NULL, 0);
+ if (node == NULL) {
+ dbg_xfrin("Failed to create new node.\n");
+ knot_packet_free(&packet);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return KNOT_ENOMEM;
+ }
+ dbg_xfrin("Created new node for the record.\n");
+
+ // insert the RRSet to the node
+ ret = knot_node_add_rrset(node, rr, 1);
+ if (ret < 0) {
+ dbg_xfrin("Failed to add RRSet to node (%s"
+ ")\n", knot_strerror(ret));
+ knot_packet_free(&packet);
+ knot_node_free(&node, 1, 0); // ???
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return KNOT_ERROR;
+ } else if (ret > 0) {
+ // should not happen, this is new node
+ assert(0);
+// knot_rrset_deep_free(&rr, 1, 0, 0);
+ }
+
+ // insert the node into the zone
+ ret = add_node(zone, node, 1, 0, 1);
+ assert(node != NULL);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add node to zone (%s)"
+ ".\n", knot_strerror(ret));
+ knot_packet_free(&packet);
+ knot_node_free(&node, 1, 0); // ???
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ return KNOT_ERROR;
+ }
+
+ in_zone = 1;
+ } else {
+ assert(in_zone);
+
+ ret = knot_zone_contents_add_rrset(zone, rr, &node,
+ KNOT_RRSET_DUPL_MERGE, 1);
+ if (ret < 0) {
+ dbg_xfrin("Failed to add RRSet to zone:"
+ "%s.\n", knot_strerror(ret));
+ return KNOT_ERROR;
+ } else if (ret > 0) {
+ // merged, free the RRSet
+// knot_rrset_deep_free(&rr, 1, 0, 0);
+ knot_rrset_free(&rr);
+ }
+
+ }
+
+ rr = NULL;
+
+ // parse next RR
+ ret = knot_packet_parse_next_rr_answer(packet, &rr);
+ }
+
+ assert(ret != KNOT_EOK || rr == NULL);
+
+ if (ret < 0) {
+ // some error in parsing
+ dbg_xfrin("Could not parse next RR: %s.\n",
+ knot_strerror(ret));
+ knot_packet_free(&packet);
+ knot_node_free(&node, 0, 0);
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ /*! \todo Cleanup. */
+ return KNOT_EMALF;
+ }
+
+ assert(ret == KNOT_EOK);
+ assert(rr == NULL);
+
+ // if the last node is not yet in the zone, insert
+ if (!in_zone) {
+ assert(node != NULL);
+ ret = knot_zone_contents_add_node(zone, node, 1, 0, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add last node into zone (%s)"
+ ".\n", knot_strerror(ret));
+ knot_packet_free(&packet);
+ knot_node_free(&node, 1, 0);
+ return KNOT_ERROR; /*! \todo Other error */
+ }
+ }
+
+ /*! \note [TSIG] Now check if there is not a TSIG record at the end of
+ * the packet.
+ */
+ ret = xfrin_check_tsig(packet, xfr,
+ knot_ns_tsig_required(xfr->packet_nr));
+ ++xfr->packet_nr;
+
+ knot_packet_free(&packet);
+ dbg_xfrin("Processed one AXFR packet successfully.\n");
+
+ /*! \note [TSIG] TSIG errors are propagated and reported in a standard
+ * manner, as we're in response processing, no further error response
+ * should be sent.
+ */
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_parse_first_rr(knot_packet_t **packet, const uint8_t *pkt,
+ size_t size, knot_rrset_t **rr)
+{
+ *packet = knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ if (packet == NULL) {
+ dbg_xfrin("Could not create packet structure.\n");
+ return KNOT_ENOMEM;
+ }
+
+ int ret = knot_packet_parse_from_wire(*packet, pkt, size, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Could not parse packet: %s.\n",
+ knot_strerror(ret));
+ knot_packet_free(packet);
+ return KNOT_EMALF;
+ }
+
+ // check if the TC bit is set (it must not be)
+ if (knot_wire_get_tc(pkt)) {
+ dbg_xfrin("IXFR response has TC bit set.\n");
+ knot_packet_free(packet);
+ return KNOT_EMALF;
+ }
+
+ ret = knot_packet_parse_next_rr_answer(*packet, rr);
+
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Could not parse first Answer RR: %s.\n",
+ knot_strerror(ret));
+ knot_packet_free(packet);
+ return KNOT_EMALF;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int xfrin_process_ixfr_packet(/*const uint8_t *pkt, size_t size,
+ knot_changesets_t **chs*/knot_ns_xfr_t *xfr)
+{
+ size_t size = xfr->wire_size;
+ const uint8_t *pkt = xfr->wire;
+ knot_changesets_t **chs = (knot_changesets_t **)(&xfr->data);
+
+ if (pkt == NULL || chs == NULL) {
+ dbg_xfrin("Wrong parameters supported.\n");
+ return KNOT_EBADARG;
+ }
+
+ // check if the response is OK
+ if (knot_wire_get_rcode(pkt) != KNOT_RCODE_NOERROR) {
+ return KNOT_EXFRREFUSED;
+ }
+
+ knot_packet_t *packet = NULL;
+// knot_rrset_t *soa1 = NULL;
+// knot_rrset_t *soa2 = NULL;
+ knot_rrset_t *rr = NULL;
+
+ int ret;
+
+ if ((ret = xfrin_parse_first_rr(&packet, pkt, size, &rr)) != KNOT_EOK) {
+ return ret;
+ }
+
+ assert(packet != NULL);
+
+ // state of the transfer
+ // -1 .. a SOA is expected to create a new changeset
+ int state = 0;
+
+ if (rr == NULL) {
+ dbg_xfrin("No RRs in the packet.\n");
+ knot_packet_free(&packet);
+ /*! \todo Some other action??? */
+ return KNOT_EMALF;
+ }
+
+ if (*chs == NULL) {
+ dbg_xfrin("Changesets empty, creating new.\n");
+
+ ret = knot_changeset_allocate(chs);
+ if (ret != KNOT_EOK) {
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ knot_packet_free(&packet);
+ return ret;
+ }
+
+ // the first RR must be a SOA
+ if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) {
+ dbg_xfrin("First RR is not a SOA RR!\n");
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ ret = KNOT_EMALF;
+ goto cleanup;
+ }
+
+ // just store the first SOA for later use
+ (*chs)->first_soa = rr;
+ state = -1;
+
+ dbg_xfrin("First SOA of IXFR saved, state set to -1.\n");
+
+ // parse the next one
+ ret = knot_packet_parse_next_rr_answer(packet, &rr);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ /*
+ * If there is no other records in the response than the SOA, it
+ * means one of these two cases:
+ *
+ * 1) The server does not have newer zone than ours.
+ * This is indicated by serial equal to the one of our zone.
+ * 2) The server wants to send the transfer but is unable to fit
+ * it in the packet. This is indicated by serial different
+ * (newer) from the one of our zone.
+ *
+ * The serials must be compared in other parts of the server, so
+ * just indicate that the answer contains only one SOA.
+ */
+ if (rr == NULL) {
+ dbg_xfrin("Response containing only SOA,\n");
+ knot_packet_free(&packet);
+ return XFRIN_RES_SOA_ONLY;
+ } else if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) {
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ dbg_xfrin("Fallback to AXFR.\n");
+ ret = XFRIN_RES_FALLBACK;
+ knot_free_changesets(chs);
+ xfr->data = 0;
+ return ret;
+ }
+ } else {
+ if ((*chs)->first_soa == NULL) {
+ dbg_xfrin("Changesets don't contain frist SOA!\n");
+ ret = KNOT_EBADARG;
+ goto cleanup;
+ }
+ dbg_xfrin("Changesets present.\n");
+ }
+
+ /*
+ * Process the next RR. Different requirements are in place in
+ * different cases:
+ *
+ * 1) Last changeset has both soa_from and soa_to.
+ * a) The next RR is a SOA.
+ * i) The next RR is equal to the first_soa saved in changesets.
+ * This denotes the end of the transfer. It may be dropped and
+ * the end should be signalised by returning positive value.
+ *
+ * ii) The next RR is some other SOA.
+ * This means a start of new changeset - create it and add it
+ * to the list.
+ *
+ * b) The next RR is not a SOA.
+ * Put the RR into the ADD part of the last changeset as this is
+ * not finished yet. Continue while SOA is not encountered. Then
+ * jump to 1-a.
+ *
+ * 2) Last changeset has only the soa_from and does not have soa_to.
+ * a) The next RR is a SOA.
+ * This means start of the ADD section. Put the SOA to the
+ * changeset. Continue adding RRs to the ADD section while SOA
+ * is not encountered. This is identical to 1-b.
+ *
+ * b) The next RR is not a SOA.
+ * This means the REMOVE part is not finished yet. Add the RR to
+ * the REMOVE part. Continue adding next RRs until a SOA is
+ * encountered. Then jump to 2-a.
+ */
+
+ // first, find out in what state we are
+ /*! \todo It would be more elegant to store the state in the
+ * changesets structure, or in some place persistent between
+ * calls to this function.
+ */
+ if (state != -1) {
+ dbg_xfrin("State is not -1, deciding...\n");
+ // there should be at least one started changeset right now
+ if ((*chs)->count <= 0) {
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ ret = KNOT_EMALF;
+ goto cleanup;
+ }
+
+ // a changeset should be created only when there is a SOA
+ assert((*chs)->sets[(*chs)->count - 1].soa_from != NULL);
+
+ if ((*chs)->sets[(*chs)->count - 1].soa_to == NULL) {
+ state = XFRIN_CHANGESET_REMOVE;
+ } else {
+ state = XFRIN_CHANGESET_ADD;
+ }
+ }
+
+ dbg_xfrin("State before the loop: %d\n", state);
+
+ /*! \todo This may be implemented with much less IFs! */
+
+ while (ret == KNOT_EOK && rr != NULL) {
+dbg_xfrin_exec(
+ dbg_xfrin("Next loop, state: %d\n", state);
+ char *name = knot_dname_to_str(knot_rrset_owner(rr));
+ dbg_xfrin("Actual RR: %s, type %s.\n", name,
+ knot_rrtype_to_string(knot_rrset_type(rr)));
+ free(name);
+);
+ switch (state) {
+ case -1:
+ // a SOA is expected
+ // this may be either a start of a changeset or the
+ // last SOA (in case the transfer was empty, but that
+ // is quite weird in fact
+ if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) {
+ dbg_xfrin("First RR is not a SOA RR!\n");
+ dbg_xfrin("RR type: %s\n",
+ knot_rrtype_to_string(knot_rrset_type(rr)));
+ ret = KNOT_EMALF;
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ goto cleanup;
+ }
+
+ if (knot_rdata_soa_serial(knot_rrset_rdata(rr))
+ == knot_rdata_soa_serial(
+ knot_rrset_rdata((*chs)->first_soa))) {
+
+ /*! \note [TSIG] Check TSIG, we're at the end of
+ * transfer.
+ */
+ ret = xfrin_check_tsig(packet, xfr, 1);
+
+ // last SOA, discard and end
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ knot_packet_free(&packet);
+
+ /*! \note [TSIG] If TSIG validates, consider
+ * transfer complete. */
+ if (ret == KNOT_EOK) {
+ ret = XFRIN_RES_COMPLETE;
+ }
+
+ return ret;
+ } else {
+ // normal SOA, start new changeset
+ (*chs)->count++;
+ if ((ret = knot_changesets_check_size(*chs))
+ != KNOT_EOK) {
+ (*chs)->count--;
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ goto cleanup;
+ }
+
+ ret = knot_changeset_add_soa(
+ &(*chs)->sets[(*chs)->count - 1], rr,
+ XFRIN_CHANGESET_REMOVE);
+ if (ret != KNOT_EOK) {
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ goto cleanup;
+ }
+
+ // change state to REMOVE
+ state = XFRIN_CHANGESET_REMOVE;
+ }
+ break;
+ case XFRIN_CHANGESET_REMOVE:
+ // if the next RR is SOA, store it and change state to
+ // ADD
+ if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) {
+ // we should not be here if soa_from is not set
+ assert((*chs)->sets[(*chs)->count - 1].soa_from
+ != NULL);
+
+ ret = knot_changeset_add_soa(
+ &(*chs)->sets[(*chs)->count - 1], rr,
+ XFRIN_CHANGESET_ADD);
+ if (ret != KNOT_EOK) {
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ goto cleanup;
+ }
+
+ state = XFRIN_CHANGESET_ADD;
+ } else {
+ // just add the RR to the REMOVE part and
+ // continue
+ if ((ret = knot_changeset_add_new_rr(
+ &(*chs)->sets[(*chs)->count - 1], rr,
+ XFRIN_CHANGESET_REMOVE)) != KNOT_EOK) {
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ goto cleanup;
+ }
+ }
+ break;
+ case XFRIN_CHANGESET_ADD:
+ // if the next RR is SOA change to state -1 and do not
+ // parse next RR
+ if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) {
+ state = -1;
+ continue;
+ } else {
+
+ // just add the RR to the ADD part and continue
+ if ((ret = knot_changeset_add_new_rr(
+ &(*chs)->sets[(*chs)->count - 1], rr,
+ XFRIN_CHANGESET_ADD)) != KNOT_EOK) {
+ knot_rrset_deep_free(&rr, 1, 1, 1);
+ goto cleanup;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ // parse the next RR
+ dbg_xfrin("Parsing next RR..\n");
+ ret = knot_packet_parse_next_rr_answer(packet, &rr);
+ dbg_xfrin("Returned %d, %p.\n", ret, rr);
+ }
+
+ /*! \note Check TSIG, we're at the end of packet. It may not be
+ * required.
+ */
+ ret = xfrin_check_tsig(packet, xfr,
+ knot_ns_tsig_required(xfr->packet_nr));
+ dbg_xfrin_detail("xfrin_check_tsig() returned %d\n", ret);
+ ++xfr->packet_nr;
+
+ /*! \note [TSIG] Cleanup and propagate error if TSIG validation fails.*/
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
+
+ // here no RRs remain in the packet but the transfer is not finished
+ // yet, return EOK
+ knot_packet_free(&packet);
+ return KNOT_EOK;
+
+cleanup:
+ /* We should go here only if some error occured. */
+ assert(ret < 0);
+
+ dbg_xfrin("Cleanup after processing IXFR/IN packet.\n");
+ knot_free_changesets(chs);
+ knot_packet_free(&packet);
+ xfr->data = 0;
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Applying changesets to zone */
+/*----------------------------------------------------------------------------*/
+
+typedef struct {
+ /*!
+ * Deleted (without owners and RDATA) after successful update.
+ */
+ knot_rrset_t **old_rrsets;
+ int old_rrsets_count;
+ int old_rrsets_allocated;
+
+ /*!
+ * Deleted after successful update.
+ */
+ knot_rdata_t **old_rdata;
+ uint *old_rdata_types;
+ int old_rdata_count;
+ int old_rdata_allocated;
+
+ /*!
+ * \brief Copied RRSets (i.e. modified by the update).
+ *
+ * Deleted (without owners and RDATA) after failed update.
+ */
+ knot_rrset_t **new_rrsets;
+ int new_rrsets_count;
+ int new_rrsets_allocated;
+
+ /*!
+ * Deleted (without contents) after successful update.
+ */
+ knot_node_t **old_nodes;
+ int old_nodes_count;
+ int old_nodes_allocated;
+
+ /*!
+ * Deleted (without contents) after failed update.
+ */
+ knot_node_t **new_nodes;
+ int new_nodes_count;
+ int new_nodes_allocated;
+
+ ck_hash_table_item_t **old_hash_items;
+ int old_hash_items_count;
+ int old_hash_items_allocated;
+} xfrin_changes_t;
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_changes_free(xfrin_changes_t **changes)
+{
+ free((*changes)->old_nodes);
+ free((*changes)->old_rrsets);
+ free((*changes)->old_rdata);
+ free((*changes)->old_rdata_types);
+ free((*changes)->new_rrsets);
+ free((*changes)->new_nodes);
+ free((*changes)->old_hash_items);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_changes_check_rrsets(knot_rrset_t ***rrsets,
+ int *count, int *allocated, int to_add)
+{
+ /* Ensure at least requested size is allocated. */
+ int new_count = (*count + to_add);
+ assert(new_count >= 0);
+ if (new_count <= *allocated) {
+ return KNOT_EOK;
+ }
+
+ /* Allocate new memory block. */
+ knot_rrset_t **rrsets_new = malloc(new_count * sizeof(knot_rrset_t *));
+ if (rrsets_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Initialize new memory and copy old data. */
+ memset(rrsets_new, 0, new_count * sizeof(knot_rrset_t *));
+ memcpy(rrsets_new, *rrsets, (*allocated) * sizeof(knot_rrset_t *));
+
+ /* Free old nodes and switch pointers. */
+ free(*rrsets);
+ *rrsets = rrsets_new;
+ *allocated = new_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_changes_check_nodes(knot_node_t ***nodes,
+ int *count, int *allocated)
+{
+ assert(nodes != NULL);
+ assert(count != NULL);
+ assert(allocated != 0);
+
+ /* Ensure at least count and some reserve is allocated. */
+ int new_count = *count + 2;
+ if (new_count <= *allocated) {
+ return KNOT_EOK;
+ }
+
+ /* Allocate new memory block. */
+ const size_t node_len = sizeof(knot_node_t *);
+ knot_node_t **nodes_new = malloc(new_count * node_len);
+ if (nodes_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Clear memory block and copy old data. */
+ memset(nodes_new, 0, new_count * node_len);
+ memcpy(nodes_new, *nodes, (*allocated) * node_len);
+
+ /* Free old nodes and switch pointers. */
+ free(*nodes);
+ *nodes = nodes_new;
+ *allocated = new_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types,
+ int count, int *allocated, int to_add)
+{
+ /* Ensure at least requested size is allocated. */
+ int new_count = (count + to_add);
+ assert(new_count >= 0);
+ if (new_count <= *allocated) {
+ return KNOT_EOK;
+ }
+
+ /* Allocate new memory block. */
+ knot_rdata_t **rdatas_new = malloc(new_count * sizeof(knot_rdata_t *));
+ if (rdatas_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ uint *types_new = malloc(new_count * sizeof(uint));
+ if (types_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Initialize new memory and copy old data. */
+ memset(rdatas_new, 0, new_count * sizeof(knot_rdata_t *));
+ memcpy(rdatas_new, *rdatas, (*allocated) * sizeof(knot_rdata_t *));
+
+ memset(types_new, 0, new_count * sizeof(uint));
+ memcpy(types_new, *types, (*allocated) * sizeof(uint));
+
+ /* Free old rdatas and switch pointers. */
+ free(*rdatas);
+ free(*types);
+ *rdatas = rdatas_new;
+ *types = types_new;
+ *allocated = new_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_changes_check_hash_items(ck_hash_table_item_t ***items,
+ int *count, int *allocated)
+{
+ /* Prevent infinite loop in case of allocated = 0. */
+ int new_count = 0;
+ if (*allocated == 0) {
+ new_count = *count + 1;
+ } else {
+ if (*count == *allocated) {
+ new_count = *allocated * 2;
+ }
+ }
+
+ const size_t item_len = sizeof(ck_hash_table_item_t *);
+ ck_hash_table_item_t **items_new = malloc(new_count * item_len);
+ if (items_new == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ memset(items_new, 0, new_count * item_len);
+ memcpy(items_new, *items, (*count) * item_len);
+ free(*items);
+ *items = items_new;
+ *allocated = new_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_zone_contents_free(knot_zone_contents_t **contents)
+{
+ /*! \todo This should be all in some API!! */
+
+ if ((*contents)->table != NULL) {
+// ck_destroy_table(&(*contents)->table, NULL, 0);
+ ck_table_free(&(*contents)->table);
+ }
+
+ // free the zone tree, but only the structure
+ // (nodes are already destroyed)
+ dbg_zone("Destroying zone tree.\n");
+ knot_zone_tree_free(&(*contents)->nodes);
+ dbg_zone("Destroying NSEC3 zone tree.\n");
+ knot_zone_tree_free(&(*contents)->nsec3_nodes);
+
+ knot_nsec3_params_free(&(*contents)->nsec3_params);
+
+ knot_dname_table_deep_free(&(*contents)->dname_table);
+
+ free(*contents);
+ *contents = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_rollback_update(knot_zone_contents_t *contents,
+ xfrin_changes_t *changes)
+{
+ /*
+ * This function is called only when no references were actually set to
+ * the new nodes, just the new nodes reference other.
+ * We thus do not need to fix any references, just from the old nodes
+ * to the new ones.
+ */
+
+ // discard new nodes, but do not remove RRSets from them
+ for (int i = 0; i < changes->new_nodes_count; ++i) {
+ knot_node_free(&changes->new_nodes[i], 0, 0);
+ }
+
+ // set references from old nodes to new nodes to NULL and remove the
+ // old flag
+ for (int i = 0; i < changes->old_nodes_count; ++i) {
+ knot_node_set_new_node(changes->old_nodes[i], NULL);
+ knot_node_clear_old(changes->old_nodes[i]);
+ }
+
+ // discard new RRSets
+ for (int i = 0; i < changes->old_rrsets_count; ++i) {
+ knot_rrset_deep_free(&changes->new_rrsets[i], 0, 1, 0);
+ }
+
+ // destroy the shallow copy of zone
+ xfrin_zone_contents_free(&contents);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static knot_rdata_t *xfrin_remove_rdata(knot_rrset_t *from,
+ const knot_rrset_t *what)
+{
+ knot_rdata_t *old = NULL;
+ knot_rdata_t *old_actual = NULL;
+
+ const knot_rdata_t *rdata = knot_rrset_rdata(what);
+
+ while (rdata != NULL) {
+ old_actual = knot_rrset_remove_rdata(from, rdata);
+ if (old_actual != NULL) {
+ old_actual->next = old;
+ old = old_actual;
+ }
+ rdata = knot_rrset_rdata_next(what, rdata);
+ }
+
+ return old;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_get_node_copy(knot_node_t **node, xfrin_changes_t *changes)
+{
+ knot_node_t *new_node =
+ knot_node_get_new_node(*node);
+ if (new_node == NULL) {
+ dbg_xfrin("Creating copy of node.\n");
+ int ret = knot_node_shallow_copy(*node, &new_node);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to create node copy.\n");
+ return KNOT_ENOMEM;
+ }
+
+ dbg_xfrin_detail("Created copy of old node %p to new node %p\n",
+ *node, new_node);
+
+ assert(changes);
+
+// changes->new_nodes_allocated = 0;
+
+ // save the copy of the node
+ ret = xfrin_changes_check_nodes(
+ &changes->new_nodes,
+ &changes->new_nodes_count,
+ &changes->new_nodes_allocated);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add new node to list.\n");
+ knot_node_free(&new_node, 0, 0);
+ return ret;
+ }
+
+// changes->old_nodes_allocated = 0;
+
+ // save the old node to list of old nodes
+ ret = xfrin_changes_check_nodes(
+ &changes->old_nodes,
+ &changes->old_nodes_count,
+ &changes->old_nodes_allocated);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add old node to list.\n");
+ knot_node_free(&new_node, 0, 0);
+ return ret;
+ }
+
+ assert(changes->new_nodes);
+ assert(changes->old_nodes);
+
+ changes->new_nodes[changes->new_nodes_count++] = new_node;
+ changes->old_nodes[changes->old_nodes_count++] = *node;
+
+ // mark the old node as old
+ knot_node_set_old(*node);
+
+ knot_node_set_new(new_node);
+ knot_node_set_new_node(*node, new_node);
+ }
+
+ *node = new_node;
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy,
+ xfrin_changes_t *changes)
+{
+ // create new RRSet by copying the old one
+ int ret = knot_rrset_shallow_copy(old, copy);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to create RRSet copy.\n");
+ return KNOT_ENOMEM;
+ }
+
+ // add the RRSet to the list of new RRSets
+ ret = xfrin_changes_check_rrsets(&changes->new_rrsets,
+ &changes->new_rrsets_count,
+ &changes->new_rrsets_allocated, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add new RRSet to list.\n");
+ knot_rrset_free(copy);
+ return ret;
+ }
+
+ changes->new_rrsets[changes->new_rrsets_count++] = *copy;
+
+ // add the old RRSet to the list of old RRSets
+ ret = xfrin_changes_check_rrsets(&changes->old_rrsets,
+ &changes->old_rrsets_count,
+ &changes->old_rrsets_allocated, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add old RRSet to list.\n");
+ return ret;
+ }
+
+ changes->old_rrsets[changes->old_rrsets_count++] = old;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_copy_rrset(knot_node_t *node, knot_rr_type_t type,
+ knot_rrset_t **rrset, xfrin_changes_t *changes)
+{
+ knot_rrset_t *old = knot_node_remove_rrset(node, type);
+
+ if (old == NULL) {
+ dbg_xfrin("RRSet not found for RR to be removed.\n");
+ return 1;
+ }
+
+ int ret = xfrin_copy_old_rrset(old, rrset, changes);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ dbg_xfrin_detail("Copied old rrset %p to new %p.\n",
+ old, *rrset);
+
+ // replace the RRSet in the node copy by the new one
+ ret = knot_node_add_rrset(node, *rrset, 0);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add RRSet copy to node\n");
+ return KNOT_ERROR;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_remove_rrsigs(xfrin_changes_t *changes,
+ const knot_rrset_t *remove,
+ knot_node_t *node,
+ knot_rrset_t **rrset)
+{
+ assert(changes != NULL);
+ assert(remove != NULL);
+ assert(node != NULL);
+ assert(rrset != NULL);
+ assert(knot_rrset_type(remove) == KNOT_RRTYPE_RRSIG);
+
+ /*! \todo These optimalizations may be useless as there may be only
+ * one RRSet of each type and owner in the changeset.
+ */
+
+ int ret;
+
+ if (!*rrset
+ || knot_dname_compare(knot_rrset_owner(*rrset),
+ knot_node_owner(node)) != 0
+ || knot_rrset_type(*rrset) != knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(remove))) {
+ // find RRSet based on the Type Covered
+ knot_rr_type_t type = knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(remove));
+
+ // copy the rrset
+ ret = xfrin_copy_rrset(node, type, rrset, changes);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to copy rrset from changeset.\n");
+ return ret;
+ }
+ } else {
+ // we should have the right RRSIG RRSet in *rrset
+ assert(knot_rrset_type(*rrset)
+ == knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(remove)));
+ // this RRSet should be the already copied RRSet so we may
+ // update it right away
+ }
+
+ // get the old rrsigs
+ knot_rrset_t *old = knot_rrset_get_rrsigs(*rrset);
+ if (old == NULL) {
+ return 1;
+ }
+
+ // copy the RRSIGs
+ /*! \todo This may be done unnecessarily more times. */
+ knot_rrset_t *rrsigs;
+ ret = xfrin_copy_old_rrset(old, &rrsigs, changes);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // set the RRSIGs to the new RRSet copy
+ if (knot_rrset_set_rrsigs(*rrset, rrsigs) != KNOT_EOK) {
+ dbg_xfrin("Failed to set rrsigs.\n");
+ return KNOT_ERROR;
+ }
+
+
+
+ // now in '*rrset' we have a copy of the RRSet which holds the RRSIGs
+ // and in 'rrsigs' we have the copy of the RRSIGs
+
+ knot_rdata_t *rdata = xfrin_remove_rdata(rrsigs, remove);
+ if (rdata == NULL) {
+ dbg_xfrin("Failed to remove RDATA from RRSet: %s.\n",
+ knot_strerror(ret));
+ return 1;
+ }
+
+ // if the RRSet is empty, remove from node and add to old RRSets
+ // check if there is no RRSIGs; if there are, leave the RRSet
+ // there; it may be eventually removed when the RRSIGs are removed
+ if (knot_rrset_rdata(rrsigs) == NULL) {
+ // remove the RRSIGs from the RRSet
+ knot_rrset_set_rrsigs(*rrset, NULL);
+
+ ret = xfrin_changes_check_rrsets(&changes->old_rrsets,
+ &changes->old_rrsets_count,
+ &changes->old_rrsets_allocated,
+ 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add empty RRSet to the "
+ "list of old RRSets.");
+ // delete the RRSet right away
+ knot_rrset_free(&rrsigs);
+ return ret;
+ }
+
+ changes->old_rrsets[changes->old_rrsets_count++] = rrsigs;
+
+ // now check if the RRSet is not totally empty
+ if (knot_rrset_rdata(*rrset) == NULL) {
+ assert(knot_rrset_rrsigs(*rrset) == NULL);
+
+ // remove the whole RRSet from the node
+ knot_rrset_t *tmp = knot_node_remove_rrset(node,
+ knot_rrset_type(*rrset));
+ assert(tmp == *rrset);
+
+ ret = xfrin_changes_check_rrsets(&changes->old_rrsets,
+ &changes->old_rrsets_count,
+ &changes->old_rrsets_allocated,
+ 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add empty RRSet to "
+ "the list of old RRSets.");
+ // delete the RRSet right away
+ knot_rrset_free(rrset);
+ return ret;
+ }
+
+ changes->old_rrsets[changes->old_rrsets_count++] =
+ *rrset;
+ }
+ }
+
+ // connect the RDATA to the list of old RDATA
+ ret = xfrin_changes_check_rdata(&changes->old_rdata,
+ &changes->old_rdata_types,
+ changes->old_rdata_count,
+ &changes->old_rdata_allocated, 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ changes->old_rdata[changes->old_rdata_count] = rdata;
+ changes->old_rdata_types[changes->old_rdata_count] =
+ knot_rrset_type(remove);
+ ++changes->old_rdata_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_remove_normal(xfrin_changes_t *changes,
+ const knot_rrset_t *remove,
+ knot_node_t *node,
+ knot_rrset_t **rrset)
+{
+ assert(changes != NULL);
+ assert(remove != NULL);
+ assert(node != NULL);
+ assert(rrset != NULL);
+
+ int ret;
+
+ dbg_xfrin_detail("Removing RRSet: \n");
+ knot_rrset_dump(remove, 0);
+
+ // now we have the copy of the node, so lets get the right RRSet
+ // check if we do not already have it
+ if (!*rrset
+ || knot_dname_compare(knot_rrset_owner(*rrset),
+ knot_node_owner(node)) != 0
+ || knot_rrset_type(*rrset)
+ != knot_rrset_type(remove)) {
+ /*!
+ * \todo This may happen also with already
+ * copied RRSet. In that case it would be
+ * an unnecesary overhead but will
+ * probably not cause problems. TEST!!
+ */
+ ret = xfrin_copy_rrset(node,
+ knot_rrset_type(remove), rrset, changes);
+ dbg_xfrin_detail("Copied RRSet:\n");
+ knot_rrset_dump(*rrset, 0);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ if (*rrset == NULL) {
+ dbg_xfrin("RRSet not found for RR to be removed.\n");
+ return 1;
+ }
+
+dbg_xfrin_exec(
+ char *name = knot_dname_to_str(knot_rrset_owner(*rrset));
+ dbg_xfrin("Updating RRSet with owner %s, type %s\n", name,
+ knot_rrtype_to_string(knot_rrset_type(*rrset)));
+ free(name);
+);
+
+ // remove the specified RRs from the RRSet (de facto difference of
+ // sets)
+ knot_rdata_t *rdata = xfrin_remove_rdata(*rrset, remove);
+ if (rdata == NULL) {
+ dbg_xfrin("Failed to remove RDATA from RRSet: %s.\n",
+ knot_strerror(ret));
+ return 1;
+ }
+
+dbg_xfrin_exec_detail(
+ dbg_xfrin_detail("Removed rdata: \n");
+ knot_rdata_t *r = rdata;
+ if (r != NULL) {
+ do {
+ dbg_xfrin_detail("pointer: %p\n", r);
+ knot_rdata_dump(r, knot_rrset_type(remove), 0);
+ r = r->next;
+ } while (r != NULL && r != rdata);
+ }
+);
+
+ // if the RRSet is empty, remove from node and add to old RRSets
+ // check if there is no RRSIGs; if there are, leave the RRSet
+ // there; it may be eventually removed when the RRSIGs are removed
+ if (knot_rrset_rdata(*rrset) == NULL
+ && knot_rrset_rrsigs(*rrset) == NULL) {
+
+ knot_rrset_t *tmp = knot_node_remove_rrset(node,
+ knot_rrset_type(*rrset));
+ dbg_xfrin_detail("Removed whole RRSet (%p).\n", tmp);
+
+ // add the removed RRSet to list of old RRSets
+
+ assert(tmp == *rrset);
+ ret = xfrin_changes_check_rrsets(&changes->old_rrsets,
+ &changes->old_rrsets_count,
+ &changes->old_rrsets_allocated,
+ 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add empty RRSet to the "
+ "list of old RRSets.");
+ // delete the RRSet right away
+ knot_rrset_free(rrset);
+ return ret;
+ }
+
+ changes->old_rrsets[changes->old_rrsets_count++] = *rrset;
+ }
+
+ // connect the RDATA to the list of old RDATA
+ ret = xfrin_changes_check_rdata(&changes->old_rdata,
+ &changes->old_rdata_types,
+ changes->old_rdata_count,
+ &changes->old_rdata_allocated, 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ changes->old_rdata[changes->old_rdata_count] = rdata;
+ changes->old_rdata_types[changes->old_rdata_count] =
+ knot_rrset_type(remove);
+ ++changes->old_rdata_count;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_remove_all_rrsets(xfrin_changes_t *changes,
+ knot_node_t *node, uint16_t type)
+{
+ /*! \todo Implement. */
+ int ret;
+
+ if (type == KNOT_RRTYPE_ANY) {
+ // put all the RRSets to the changes structure
+ ret = xfrin_changes_check_rrsets(&changes->old_rrsets,
+ &changes->old_rrsets_count,
+ &changes->old_rrsets_allocated,
+ knot_node_rrset_count(node));
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to check changeset rrsets.\n");
+ return ret;
+ }
+
+ knot_rrset_t **rrsets = knot_node_get_rrsets(node);
+ knot_rrset_t **place = changes->old_rrsets
+ + changes->old_rrsets_count;
+ /*! \todo Test this!!! */
+ memcpy(place, rrsets, knot_node_rrset_count(node) * sizeof(knot_rrset_t *));
+
+ // remove all RRSets from the node
+ knot_node_remove_all_rrsets(node);
+ } else {
+ ret = xfrin_changes_check_rrsets(&changes->old_rrsets,
+ &changes->old_rrsets_count,
+ &changes->old_rrsets_allocated,
+ 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to check changeset rrsets.\n");
+ return ret;
+ }
+ // remove only RRSet with the given type
+ knot_rrset_t *rrset = knot_node_remove_rrset(node, type);
+ changes->old_rrsets[changes->old_rrsets_count++] = rrset;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_remove(knot_zone_contents_t *contents,
+ knot_changeset_t *chset,
+ xfrin_changes_t *changes)
+{
+ /*
+ * Iterate over removed RRSets, copy appropriate nodes and remove
+ * the rrsets from them. By default, the RRSet should be copied so that
+ * RDATA may be removed from it.
+ */
+ int ret = 0;
+ knot_node_t *node = NULL;
+ knot_rrset_t *rrset = NULL;
+
+ for (int i = 0; i < chset->remove_count; ++i) {
+ // check if the old node is not the one we should use
+ if (!node || knot_rrset_owner(chset->remove[i])
+ != knot_node_owner(node)) {
+ node = knot_zone_contents_get_node(contents,
+ knot_rrset_owner(chset->remove[i]));
+ if (node == NULL) {
+ dbg_xfrin("Node not found for RR to be removed"
+ "!\n");
+ continue;
+ }
+ }
+
+ // create a copy of the node if not already created
+ if (!knot_node_is_new(node)) {
+ ret = xfrin_get_node_copy(&node, changes);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ assert(node != NULL);
+ assert(knot_node_is_new(node));
+
+ // first check if all RRSets should be removed
+ if (knot_rrset_class(chset->remove[i]) == KNOT_CLASS_ANY) {
+ ret = xfrin_apply_remove_all_rrsets(
+ changes, node,
+ knot_rrset_type(chset->remove[i]));
+ } else if (knot_rrset_type(chset->remove[i])
+ == KNOT_RRTYPE_RRSIG) {
+ // this should work also for UPDATE
+ ret = xfrin_apply_remove_rrsigs(changes,
+ chset->remove[i],
+ node, &rrset);
+ } else {
+ // this should work also for UPDATE
+ ret = xfrin_apply_remove_normal(changes,
+ chset->remove[i],
+ node, &rrset);
+ }
+
+ dbg_xfrin("xfrin_apply_remove() ret = %d\n", ret);
+
+ if (ret > 0) {
+ continue;
+ } else if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static knot_node_t *xfrin_add_new_node(knot_zone_contents_t *contents,
+ knot_rrset_t *rrset)
+{
+ /*! \todo Why is the function disabled? */
+ //return NULL;
+
+ knot_node_t *node = knot_node_new(knot_rrset_get_owner(rrset),
+ NULL, KNOT_NODE_FLAGS_NEW);
+ if (node == NULL) {
+ dbg_xfrin("Failed to create a new node.\n");
+ return NULL;
+ }
+
+ int ret = 0;
+
+ // insert the node into zone structures and create parents if
+ // necessary
+// dbg_xfrin("Adding new node to zone. From owner: %s type %s\n",
+// knot_dname_to_str(node->owner),
+// knot_rrtype_to_string(rrset->type));
+// getchar();
+ if (knot_rrset_type(rrset) == KNOT_RRTYPE_NSEC3) {
+ ret = knot_zone_contents_add_nsec3_node(contents, node, 1, 0,
+ 1);
+ } else {
+ ret = knot_zone_contents_add_node(contents, node, 1,
+ KNOT_NODE_FLAGS_NEW, 1);
+ }
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add new node to zone contents.\n");
+ return NULL;
+ }
+
+ // find previous node and connect the new one to it
+ knot_node_t *prev = NULL;
+ if (knot_rrset_type(rrset) == KNOT_RRTYPE_NSEC3) {
+ prev = knot_zone_contents_get_previous_nsec3(contents,
+ knot_rrset_owner(rrset));
+ } else {
+ prev = knot_zone_contents_get_previous(contents,
+ knot_rrset_owner(rrset));
+ }
+
+ // fix prev and next pointers
+ if (prev != NULL) {
+ knot_node_set_previous(node, prev);
+ }
+
+// printf("contents owned by: %s (%p)\n",
+// knot_dname_to_str(contents->apex->owner),
+// contents);
+ assert(contents->zone != NULL);
+ knot_node_set_zone(node, contents->zone);
+
+ return node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_add_normal(xfrin_changes_t *changes,
+ knot_rrset_t *add,
+ knot_node_t *node,
+ knot_rrset_t **rrset)
+{
+ assert(changes != NULL);
+ assert(add != NULL);
+ assert(node != NULL);
+ assert(rrset != NULL);
+
+ int ret;
+
+ dbg_xfrin("applying rrset:\n");
+ knot_rrset_dump(add, 0);
+// getchar();
+
+ if (!*rrset
+ || knot_dname_compare(knot_rrset_owner(*rrset),
+ knot_node_owner(node)) != 0
+ || knot_rrset_type(*rrset)
+ != knot_rrset_type(add)) {
+ dbg_xfrin("Removing rrset!\n");
+ *rrset = knot_node_remove_rrset(node, knot_rrset_type(add));
+ }
+
+ dbg_xfrin("Removed RRSet: \n");
+ knot_rrset_dump(*rrset, 1);
+
+ if (*rrset == NULL) {
+dbg_xfrin_exec_verb(
+ char *name = knot_dname_to_str(add->owner);
+ dbg_xfrin_verb("RRSet to be added not found in zone.\n");
+ dbg_xfrin_verb("owner: %s type: %s\n", name,
+ knot_rrtype_to_string(add->type));
+ free(name);
+);
+// getchar();
+ // add the RRSet from the changeset to the node
+ /*! \todo What about domain names?? Shouldn't we use the
+ * zone-contents' version of this function??
+ */
+ ret = knot_node_add_rrset(node, add, 0);
+// ret = knot_zone_contents_add_rrset(node->zone->contents,
+// rrset, node,
+// KNOT_RRSET_DUPL_MERGE,
+// 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add RRSet to node.\n");
+ return KNOT_ERROR;
+ }
+ return 1; // return 1 to indicate the add RRSet was used
+ }
+
+ knot_rrset_t *old = *rrset;
+
+dbg_xfrin_exec(
+ char *name = knot_dname_to_str(knot_rrset_owner(*rrset));
+ dbg_xfrin("Found RRSet with owner %s, type %s\n", name,
+ knot_rrtype_to_string(knot_rrset_type(*rrset)));
+ free(name);
+);
+ knot_rrset_dump(*rrset, 1);
+ ret = xfrin_copy_old_rrset(old, rrset, changes);
+ if (ret != KNOT_EOK) {
+ assert(0);
+ return ret;
+ }
+
+// dbg_xfrin("After copy: Found RRSet with owner %s, type %s\n",
+// knot_dname_to_str((*rrset)->owner),
+// knot_rrtype_to_string(knot_rrset_type(*rrset)));
+
+ // merge the changeset RRSet to the copy
+ /* What if the update fails?
+ * The changesets will be destroyed - that will destroy 'add',
+ * and the copied RRSet will be destroyed because it is in the new
+ * rrsets list.
+ *
+ * If the update is successfull, the old RRSet will be destroyed,
+ * but the one from the changeset will be not!!
+ *
+ * TODO: add the 'add' rrset to list of old RRSets?
+ */
+ dbg_xfrin("Merging RRSets with owners: %s %s types: %d %d\n",
+ (*rrset)->owner->name, add->owner->name, (*rrset)->type,
+ add->type);
+ dbg_xfrin_detail("RDATA in RRSet1: %p, RDATA in RRSet2: %p\n",
+ (*rrset)->rdata, add->rdata);
+ ret = knot_rrset_merge((void **)rrset, (void **)&add);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to merge changeset RRSet to copy.\n");
+ return KNOT_ERROR;
+ }
+ dbg_xfrin("Merge returned: %d\n", ret);
+ knot_rrset_dump(*rrset, 1);
+ ret = knot_node_add_rrset(node, *rrset, 0);
+
+ // return 2 so that the add RRSet is removed from
+ // the changeset (and thus not deleted)
+ // and put to list of new RRSets (is this ok?)
+ // and deleted
+ return 2;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_add_rrsig(xfrin_changes_t *changes,
+ knot_rrset_t *add,
+ knot_node_t *node,
+ knot_rrset_t **rrset)
+{
+ assert(changes != NULL);
+ assert(add != NULL);
+ assert(node != NULL);
+ assert(rrset != NULL);
+ assert(knot_rrset_type(add) == KNOT_RRTYPE_RRSIG);
+
+ int ret;
+
+ knot_rr_type_t type = knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(add));
+
+ if (!*rrset
+ || knot_dname_compare(knot_rrset_owner(*rrset),
+ knot_node_owner(node)) != 0
+ || knot_rrset_type(*rrset) != knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(add))) {
+ // copy the rrset
+ ret = xfrin_copy_rrset(node, type, rrset, changes);
+ if (ret < 0) {
+ return ret;
+ }
+ } else {
+ // we should have the right RRSIG RRSet in *rrset
+ assert(knot_rrset_type(*rrset) == type);
+ // this RRSet should be the already copied RRSet so we may
+ // update it right away
+ }
+
+ if (*rrset == NULL) {
+ dbg_xfrin("RRSet to be added not found in zone.\n");
+
+ // create a new RRSet to add the RRSIGs into
+ *rrset = knot_rrset_new(knot_node_get_owner(node), type,
+ knot_rrset_class(add),
+ knot_rrset_ttl(add));
+ if (*rrset == NULL) {
+ dbg_xfrin("Failed to create new RRSet for RRSIGs.\n");
+ return KNOT_ENOMEM;
+ }
+
+ // add the RRSet from the changeset to the node
+ ret = knot_node_add_rrset(node, *rrset, 0);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add RRSet to node.\n");
+ return KNOT_ERROR;
+ }
+ }
+
+dbg_xfrin_exec(
+ char *name = knot_dname_to_str(knot_rrset_owner(*rrset));
+ dbg_xfrin("Found RRSet with owner %s, type %s\n", name,
+ knot_rrtype_to_string(knot_rrset_type(*rrset)));
+ free(name);
+);
+
+ if (knot_rrset_rrsigs(*rrset) == NULL) {
+ ret = knot_rrset_set_rrsigs(*rrset, add);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add RRSIGs to the RRSet.\n");
+ return KNOT_ERROR;
+ }
+
+ return 1;
+ } else {
+ knot_rrset_t *old = knot_rrset_get_rrsigs(*rrset);
+ assert(old != NULL);
+ knot_rrset_t *rrsig;
+
+ ret = xfrin_copy_old_rrset(old, &rrsig, changes);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // replace the old RRSIGs with the new ones
+ knot_rrset_set_rrsigs(*rrset, rrsig);
+
+ // merge the changeset RRSet to the copy
+ /*! \todo What if the update fails?
+ *
+ */
+ ret = knot_rrset_merge((void **)&rrsig, (void **)&add);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to merge changeset RRSet to copy.\n");
+ return KNOT_ERROR;
+ }
+
+ return 2;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_add(knot_zone_contents_t *contents,
+ knot_changeset_t *chset,
+ xfrin_changes_t *changes)
+{
+ // iterate over removed RRSets, copy appropriate nodes and remove
+ // the rrsets from them
+ int ret = 0;
+ knot_node_t *node = NULL;
+ knot_rrset_t *rrset = NULL;
+
+ for (int i = 0; i < chset->add_count; ++i) {
+ dbg_xfrin_detail("Adding RRSet:\n");
+ knot_rrset_dump(chset->add[i], 0);
+ // check if the old node is not the one we should use
+ if (!node || knot_rrset_owner(chset->add[i])
+ != knot_node_owner(node)) {
+ node = knot_zone_contents_get_node(contents,
+ knot_rrset_owner(chset->add[i]));
+ if (node == NULL) {
+ // create new node, connect it properly to the
+ // zone nodes
+ dbg_xfrin("Creating new node from.\n");
+ node = xfrin_add_new_node(contents,
+ chset->add[i]);
+ if (node == NULL) {
+ dbg_xfrin("Failed to create new node "
+ "in zone.\n");
+ return KNOT_ERROR;
+ }
+// continue; // continue with another RRSet
+ }
+ }
+
+ // create a copy of the node if not already created
+ if (!knot_node_is_new(node)) {
+ xfrin_get_node_copy(&node, changes);
+ }
+
+ assert(node != NULL);
+ assert(knot_node_is_new(node));
+
+ if (knot_rrset_type(chset->add[i]) == KNOT_RRTYPE_RRSIG) {
+ ret = xfrin_apply_add_rrsig(changes, chset->add[i],
+ node, &rrset);
+ } else {
+ ret = xfrin_apply_add_normal(changes, chset->add[i],
+ node, &rrset);
+ }
+
+ dbg_xfrin("xfrin_apply_..() returned %d, rrset: %p\n", ret,
+ rrset);
+
+ if (ret == 1) {
+ // the ADD RRSet was used, i.e. it should be removed
+ // from the changeset and saved in the list of new
+ // RRSets
+ ret = xfrin_changes_check_rrsets(
+ &changes->new_rrsets,
+ &changes->new_rrsets_count,
+ &changes->new_rrsets_allocated, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add old RRSet to list.\n");
+ return ret;
+ }
+
+ changes->new_rrsets[changes->new_rrsets_count++] =
+ chset->add[i];
+
+ chset->add[i] = NULL;
+ } else if (ret == 2) {
+ // the copy of the RRSet was used, but it was already
+ // stored in the new RRSets list
+ // just delete the add RRSet, but without RDATA
+ // as these were merged to the copied RRSet
+ knot_rrset_free(&chset->add[i]);
+ } else if (ret != KNOT_EOK) {
+
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \todo This must be tested!! Simulate failure somehow.
+ */
+static void xfrin_clean_changes_after_fail(xfrin_changes_t *changes)
+{
+ /* 1) Delete copies of RRSets created because they were updated.
+ * Do not delete their RDATA or owners.
+ */
+ for (int i = 0; i < changes->new_rrsets_count; ++i) {
+ knot_rrset_free(&changes->new_rrsets[i]);
+ }
+
+ /* 2) Delete copies of nodes created because they were updated.
+ * Do not delete their RRSets.
+ */
+ for (int i = 0; i < changes->new_nodes_count; ++i) {
+ knot_node_free(&changes->new_nodes[i], 0, 1);
+ }
+
+ // changesets will be deleted elsewhere
+ // so just delete the changes structure
+ xfrin_changes_free(&changes);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_replace_soa(knot_zone_contents_t *contents,
+ xfrin_changes_t *changes,
+ knot_changeset_t *chset)
+{
+ knot_node_t *node = knot_zone_contents_get_apex(contents);
+ assert(node != NULL);
+
+ int ret = 0;
+
+ // create a copy of the node if not already created
+ if (!knot_node_is_new(node)) {
+ ret = xfrin_get_node_copy(&node, changes);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ assert(knot_node_is_new(node));
+
+ // set the node copy as the apex of the contents
+ contents->apex = node;
+
+ // remove the SOA RRSet from the apex
+ knot_rrset_t *rrset = knot_node_remove_rrset(node, KNOT_RRTYPE_SOA);
+ assert(rrset != NULL);
+
+ // add the old RRSet to the list of old RRSets
+ ret = xfrin_changes_check_rrsets(&changes->old_rrsets,
+ &changes->old_rrsets_count,
+ &changes->old_rrsets_allocated, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add old RRSet to list.\n");
+ return ret;
+ }
+
+ // save also the SOA RDATA, because RDATA are not deleted with the
+ // RRSet
+ ret = xfrin_changes_check_rdata(&changes->old_rdata,
+ &changes->old_rdata_types,
+ changes->old_rdata_count,
+ &changes->old_rdata_allocated, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add old RDATA to list.\n");
+ return ret;
+ }
+
+ // save the SOA to the new RRSet, so that it is deleted if the
+ // apply fails
+ ret = xfrin_changes_check_rrsets(&changes->new_rrsets,
+ &changes->new_rrsets_count,
+ &changes->new_rrsets_allocated, 1);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add old RRSet to list.\n");
+ return ret;
+ }
+
+ changes->old_rrsets[changes->old_rrsets_count++] = rrset;
+
+ /*! \todo Maybe check if the SOA does not have more RDATA? */
+ changes->old_rdata[changes->old_rdata_count] = rrset->rdata;
+ changes->old_rdata_types[changes->old_rdata_count] = KNOT_RRTYPE_SOA;
+ ++changes->old_rdata_count;
+
+ // insert the new SOA RRSet to the node
+ dbg_xfrin_verb("Adding SOA.\n");
+ ret = knot_node_add_rrset(node, chset->soa_to, 0);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to add RRSet to node.\n");
+ return KNOT_ERROR;
+ }
+
+ changes->new_rrsets[changes->new_rrsets_count++] = chset->soa_to;
+
+ // remove the SOA from the changeset, so it will not be deleted after
+ // successful apply
+ chset->soa_to = NULL;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_apply_changeset(knot_zone_contents_t *contents,
+ xfrin_changes_t *changes,
+ knot_changeset_t *chset)
+{
+ /*
+ * Applies one changeset to the zone. Checks if the changeset may be
+ * applied (i.e. the origin SOA (soa_from) has the same serial as
+ * SOA in the zone apex.
+ */
+
+ // check if serial matches
+ /*! \todo Only if SOA is present? */
+ const knot_rrset_t *soa = knot_node_rrset(contents->apex,
+ KNOT_RRTYPE_SOA);
+ if (soa == NULL || knot_rdata_soa_serial(knot_rrset_rdata(soa))
+ != chset->serial_from) {
+ dbg_xfrin("SOA serials do not match!!\n");
+ return KNOT_ERROR;
+ }
+
+ int ret = xfrin_apply_remove(contents, chset, changes);
+ if (ret != KNOT_EOK) {
+ xfrin_clean_changes_after_fail(changes);
+ return ret;
+ }
+
+ ret = xfrin_apply_add(contents, chset, changes);
+ if (ret != KNOT_EOK) {
+ xfrin_clean_changes_after_fail(changes);
+ return ret;
+ }
+
+ /*! \todo Only if SOA is present? */
+ return xfrin_apply_replace_soa(contents, changes, chset);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_check_node_in_tree(knot_zone_tree_node_t *tnode, void *data)
+{
+ assert(tnode != NULL);
+ assert(data != NULL);
+ assert(tnode->node != NULL);
+
+ xfrin_changes_t *changes = (xfrin_changes_t *)data;
+
+ knot_node_t *node = knot_node_get_new_node(tnode->node);
+
+ if (node == NULL) {
+ // no RRSets were removed from this node, thus it cannot be
+ // empty
+ return;
+ }
+
+ dbg_xfrin("xfrin_check_node_in_tree: children of old node: %u, "
+ "children of new node: %u.\n",
+ knot_node_children(node),
+ knot_node_children(tnode->node));
+
+
+ // check if the node is empty and has no children
+ // to be sure, check also the count of children of the old node
+ if (knot_node_rrset_count(node) == 0
+ && knot_node_children(node) == 0
+ && knot_node_children(tnode->node) == 0) {
+ // in this case the new node copy should be removed
+ // but it cannot be deleted because if a rollback happens,
+ // the node must be in the new nodes list
+ // just add it to the old nodes list so that it is deleted
+ // after successful update
+
+ // set the new node of the old node to NULL
+ knot_node_set_new_node(tnode->node, NULL);
+
+ // if the parent has a new copy, decrease the number of
+ // children of that copy
+ if (knot_node_new_node(knot_node_parent(node, 0))) {
+ /*! \todo Replace by some API. */
+ --node->parent->new_node->children;
+ }
+
+ // put the new node to te list of old nodes
+ if (xfrin_changes_check_nodes(&changes->old_nodes,
+ &changes->old_nodes_count,
+ &changes->old_nodes_allocated)
+ != KNOT_EOK) {
+ /*! \todo Notify about the error!!! */
+ return;
+ }
+
+ changes->old_nodes[changes->old_nodes_count++] = node;
+
+ // leave the old node in the old node list, we will delete
+ // it later
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_finalize_remove_nodes(knot_zone_contents_t *contents,
+ xfrin_changes_t *changes)
+{
+ assert(contents != NULL);
+ assert(changes != NULL);
+
+ knot_node_t *node;
+ knot_zone_tree_node_t *removed;
+ ck_hash_table_item_t *rem_hash;
+ int ret;
+
+ for (int i = 0; i < changes->old_nodes_count; ++i) {
+ node = changes->old_nodes[i];
+
+ // if the node is marked as old and has no new node copy
+ // remove it from the zone structure but do not delete it
+ // that may be done only after the grace period
+ if (knot_node_is_old(node)
+ && knot_node_new_node(node) == NULL) {
+
+ if (knot_node_rrset(node, KNOT_RRTYPE_NSEC3)
+ != NULL) {
+ ret = knot_zone_contents_remove_nsec3_node(
+ contents, node, &removed);
+ } else {
+ ret = knot_zone_contents_remove_node(
+ contents, node, &removed, &rem_hash);
+ }
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to remove node from zone"
+ "!\n");
+ return KNOT_ENONODE;
+ }
+
+ assert(removed != NULL);
+ assert(removed->node == node);
+ // delete the tree node (not needed)
+ free(removed);
+
+ if (rem_hash != NULL) {
+ // save the removed hash table item
+ ret = xfrin_changes_check_hash_items(
+ &changes->old_hash_items,
+ &changes->old_hash_items_count,
+ &changes->old_hash_items_allocated);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to save the hash"
+ " table item to list of "
+ "old items.\n");
+ return ret;
+ }
+ changes->old_hash_items[
+ changes->old_hash_items_count++]
+ = rem_hash;
+ }
+ }
+ }
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_finalize_contents(knot_zone_contents_t *contents,
+ xfrin_changes_t *changes)
+{
+ // don't know what should have been done here, except for one thing:
+ // walk through the zone and remove empty nodes (save them in the
+ // old nodes list). But only those having no children!!!
+
+ /*
+ * Walk through the zone and remove empty nodes.
+ * We must walk backwards, so that children are processed before
+ * their parents. This will allow to remove chain of parent-children
+ * nodes.
+ * We cannot remove the nodes right away as it would modify the very
+ * structure used for walking through the zone. Just put the nodes
+ * to the list of old nodes to be removed.
+ * We must also decrease the node's parent's children count now
+ * and not when deleting the node, so that the chain of parent-child
+ * nodes may be removed.
+ */
+ knot_zone_tree_t *t = knot_zone_contents_get_nodes(contents);
+ assert(t != NULL);
+
+ // walk through the zone and select nodes to be removed
+ knot_zone_tree_reverse_apply_postorder(t, xfrin_check_node_in_tree,
+ (void *)changes);
+
+ // Do the same with NSEC3 nodes.
+ t = knot_zone_contents_get_nsec3_nodes(contents);
+ assert(t != NULL);
+
+ knot_zone_tree_reverse_apply_postorder(t, xfrin_check_node_in_tree,
+ (void *)changes);
+
+ // remove the nodes one by one
+ return xfrin_finalize_remove_nodes(contents, changes);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_fix_refs_in_node(knot_zone_tree_node_t *tnode, void *data)
+{
+ /*! \todo Passed data is always seto to NULL. */
+ assert(tnode != NULL);
+ //assert(data != NULL);
+
+ //xfrin_changes_t *changes = (xfrin_changes_t *)data;
+
+ // 1) Fix the reference to the node to the new one if there is some
+ knot_node_t *node = tnode->node;
+
+ knot_node_t *new_node = knot_node_get_new_node(node);
+ if (new_node != NULL) {
+ //assert(knot_node_rrset_count(new_node) > 0);
+ node = new_node;
+ tnode->node = new_node;
+ }
+
+ // 2) fix references from the node remaining in the zone
+ knot_node_update_refs(node);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_fix_gen_in_node(knot_zone_tree_node_t *tnode, void *data)
+{
+ /*! \todo Passed data is always seto to NULL. */
+ assert(tnode != NULL);
+
+ knot_node_t *node = tnode->node;
+
+ knot_node_set_old(node);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_fix_hash_refs(ck_hash_table_item_t *item, void *data)
+{
+ if (item == NULL) {
+ return;
+ }
+
+ knot_node_t *new_node = knot_node_get_new_node(
+ (knot_node_t *)item->value);
+ if (new_node != NULL) {
+ assert(item->key_length
+ == knot_dname_size(knot_node_owner(new_node)));
+ assert(strncmp(item->key, (const char *)knot_dname_name(
+ knot_node_owner(new_node)), item->key_length) == 0);
+ item->value = (void *)new_node;
+ item->key = (const char *)knot_dname_name(
+ knot_node_owner(new_node));
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_fix_dname_refs(knot_dname_t *dname, void *data)
+{
+ UNUSED(data);
+ knot_dname_update_node(dname);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_fix_references(knot_zone_contents_t *contents)
+{
+ /*! \todo This function must not fail!! */
+
+ /*
+ * Now the contents are already switched, and we should update all
+ * references not updated yet, so that the old contents may be removed.
+ *
+ * Walk through the zone tree, so that each node will be checked
+ * and updated.
+ */
+ // fix references in normal nodes
+ knot_zone_tree_t *tree = knot_zone_contents_get_nodes(contents);
+ knot_zone_tree_forward_apply_inorder(tree, xfrin_fix_refs_in_node,
+ NULL);
+
+ // fix refereces in NSEC3 nodes
+ tree = knot_zone_contents_get_nsec3_nodes(contents);
+ knot_zone_tree_forward_apply_inorder(tree, xfrin_fix_refs_in_node,
+ NULL);
+
+ // fix references in hash table
+ ck_hash_table_t *table = knot_zone_contents_get_hash_table(contents);
+ ck_apply(table, xfrin_fix_hash_refs, NULL);
+
+ // fix references dname table
+ int ret = knot_zone_contents_dname_table_apply(contents,
+ xfrin_fix_dname_refs, NULL);
+ assert(ret == KNOT_EOK);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int xfrin_fix_generation(knot_zone_contents_t *contents)
+{
+ assert(contents != NULL);
+
+ knot_zone_tree_t *tree = knot_zone_contents_get_nodes(contents);
+ knot_zone_tree_forward_apply_inorder(tree, xfrin_fix_gen_in_node,
+ NULL);
+
+ tree = knot_zone_contents_get_nsec3_nodes(contents);
+ knot_zone_tree_forward_apply_inorder(tree, xfrin_fix_gen_in_node,
+ NULL);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void xfrin_cleanup_update(xfrin_changes_t *changes)
+{
+ // free old nodes but do not destroy their RRSets
+ // remove owners also, because of reference counting
+ for (int i = 0; i < changes->old_nodes_count; ++i) {
+ dbg_xfrin_detail("Deleting old node: %p\n", changes->old_nodes[i]);
+ knot_node_dump(changes->old_nodes[i], 0);
+ knot_node_free(&changes->old_nodes[i], 1, 0);
+ }
+
+ // free old RRSets, and destroy also domain names in them
+ // because of reference counting
+
+ // check if there are not some duplicate RRSets
+// for (int i = 0; i < changes->old_rrsets_count; ++i) {
+// for (int j = i + 1; j < changes->old_rrsets_count; ++j) {
+// if (changes->old_rrsets[i] == changes->old_rrsets[j]) {
+// assert(0);
+// }
+// if (changes->old_rrsets[i]->rdata != NULL
+// && changes->old_rrsets[i]->rdata
+// == changes->old_rrsets[j]->rdata) {
+// assert(0);
+// }
+// }
+// }
+
+ for (int i = 0; i < changes->old_rrsets_count; ++i) {
+// knot_rrset_deep_free(&changes->old_rrsets[i], 1, 1, 1);
+ dbg_xfrin_detail("Deleting old RRSet: %p\n", changes->old_rrsets[i]);
+ knot_rrset_dump(changes->old_rrsets[i], 0);
+ knot_rrset_free(&changes->old_rrsets[i]);
+ }
+
+ // delete old RDATA
+ for (int i = 0; i < changes->old_rdata_count; ++i) {
+ dbg_xfrin_detail("Deleting old RDATA: %p, type: %s\n",
+ changes->old_rdata[i],
+ knot_rrtype_to_string(changes->old_rdata_types[i]));
+ knot_rdata_dump(changes->old_rdata[i], changes->old_rdata_types[i], 0);
+ knot_rdata_t *rdata = changes->old_rdata[i];
+ assert(rdata != NULL);
+ do {
+ knot_rdata_t *tmp = rdata->next;
+ knot_rdata_deep_free(&rdata,
+ changes->old_rdata_types[i], 1);
+ rdata = tmp;
+ } while (rdata != NULL && rdata != changes->old_rdata[i]);
+ changes->old_rdata[i] = NULL;
+ }
+
+ // free old hash table items, but do not touch their contents
+ for (int i = 0; i < changes->old_hash_items_count; ++i) {
+ free(changes->old_hash_items[i]);
+ }
+ free(changes->old_hash_items);
+
+ // free allocated arrays of nodes and rrsets
+ free(changes->new_nodes);
+ free(changes->old_nodes);
+ free(changes->new_rrsets);
+ free(changes->old_rrsets);
+ free(changes->old_rdata);
+ free(changes->old_rdata_types);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int xfrin_apply_changesets_to_zone(knot_zone_t *zone,
+ knot_changesets_t *chsets)
+{
+ if (zone == NULL || chsets == NULL || chsets->count == 0) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_contents_t *old_contents = knot_zone_get_contents(zone);
+ if (!old_contents) {
+ return KNOT_EBADARG;
+ }
+
+// dbg_xfrin("\nOLD ZONE CONTENTS:\n\n");
+// knot_zone_contents_dump(old_contents, 1);
+
+ /*
+ * Ensure that the zone generation is set to 0.
+ */
+ if (!knot_zone_contents_gen_is_old(old_contents)) {
+ // this would mean that a previous update was not completed
+ // abort
+ dbg_zone("Trying to apply changesets to zone that is "
+ "being updated. Aborting.\n");
+ return KNOT_EAGAIN;
+ }
+
+ /*
+ * Create a shallow copy of the zone, so that the structures may be
+ * updated.
+ *
+ * This will create new zone contents structures (normal nodes' tree,
+ * NSEC3 tree, hash table, domain name table), but fill them with the
+ * data from the old contents.
+ */
+ knot_zone_contents_t *contents_copy = NULL;
+
+ int ret = knot_zone_contents_shallow_copy(old_contents,
+ &contents_copy);
+ if (ret != KNOT_EOK) {
+ dbg_xfrin("Failed to create shallow copy of zone: %s\n",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ /*
+ * Now, apply one changeset after another until all are applied.
+ * Changesets may be either from IXFR or from a dynamic update.
+ * Dynamic updates use special TYPE and CLASS values to distinguish
+ * requests, such as "remove all RRSets from a node", "remove all RRs
+ * with the specified type from a node", etc.
+ *
+ * When updating anything within some node (removing RR, adding RR),
+ * the node structure is copied, but the RRSets within are not.
+ *
+ * 1) When removing RRs from node, The affected RRSet is copied. This
+ * it also a 'shallow copy', i.e. the RDATA remain the exact same.
+ * The specified RRs (i.e. RDATA) are then removed from the copied
+ * RRSet.
+ * 2) When adding RRs to node, there are two cases:
+ * a) If there is a RRSet that should contain these RRs
+ * this RRSet is copied (shallow copy) and the RRs are added to
+ * it (rrset_merge()).
+ * b) If there is not such a RRSet, the whole RRSet from the
+ * changeset is added to the new node (thus this RRSet must not
+ * be deleted afterwards).
+ *
+ * A special case are RRSIG RRs. These functions assume that they
+ * are grouped together in knot_rrset_t structures according to
+ * their header (owner, type, class) AND their 'type covered', i.e.
+ * there may be more RRSIG RRSets in one changeset (while there
+ * should not be more RRSets of any other type).
+ * 3) When removing RRSIG RRs from node, the appropriate RRSet holding
+ * them must be found (according to the 'type covered' field). This
+ * RRSet is then copied (shallow copy), Its RRSIGs are also copied
+ * and the RRSIG RRs are added to the RRSIG copy.
+ * 4) When adding RRSIG RRs to node, the same process is done - the
+ * proper RRSet holding them is found, copied, its RRSIGs are
+ * copied (if there are some) and the RRs are added to the copy.
+ *
+ * When a node is copied, reference to the copy is stored within the
+ * old node (node_t.old_node). This is important, because when the
+ * zone contents are switched to the new ones, references from old nodes
+ * that should point to new nodes are not yet set (it would influence
+ * replying from the old zone contents). While all these references
+ * (such as node_t.prev, node_t.next, node_t.parent, etc.) are properly
+ * modified, the search functions use old or new nodes accordingly
+ * (old nodes while old contents are used, new nodes when new contents
+ * are used). The 'check_version' parameter turns on this behaviour in
+ * search functions.
+ *
+ * In case of error, we must remove all data created by the update, i.e.
+ * - new nodes,
+ * - new RRSets,
+ * and remove the references to the new nodes from old nodes.
+ *
+ * In case of success, the RRSet structures from the changeset
+ * structures must not be deleted, as they are either already used by
+ * the server (stored within the new zone contents) or deleted when
+ * cleaning up the temporary 'changes' structure.
+ */
+ xfrin_changes_t changes;
+ memset(&changes, 0, sizeof(xfrin_changes_t));
+
+ for (int i = 0; i < chsets->count; ++i) {
+ if ((ret = xfrin_apply_changeset(contents_copy, &changes,
+ &chsets->sets[i])) != KNOT_EOK) {
+ xfrin_rollback_update(contents_copy, &changes);
+ dbg_xfrin("Failed to apply changesets to zone: "
+ "%s\n", knot_strerror(ret));
+ return ret;
+ }
+ }
+
+ /*
+ * When all changesets are applied, set generation 1 to the copy of
+ * the zone so that new nodes are used instead of old ones.
+ */
+// knot_zone_contents_switch_generation(contents_copy);
+ //contents_copy->generation = 1;
+ knot_zone_contents_set_gen_new(contents_copy);
+
+ /*
+ * Finalize the zone contents.
+ */
+ ret = xfrin_finalize_contents(contents_copy, &changes);
+ if (ret != KNOT_EOK) {
+ xfrin_rollback_update(contents_copy, &changes);
+ dbg_xfrin("Failed to finalize new zone contents: %s\n",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ /*
+ * Switch the zone contents
+ */
+ knot_zone_contents_t *old =
+ knot_zone_switch_contents(zone, contents_copy);
+ assert(old == old_contents);
+
+ /*
+ * From now on, the new contents of the zone are being used.
+ * References to nodes may be updated in the meantime. However, we must
+ * traverse the zone and fix all references that were not.
+ */
+ /*! \todo This operation must not fail!!! .*/
+ ret = xfrin_fix_references(contents_copy);
+ assert(ret == KNOT_EOK);
+
+ // set generation to finished
+ knot_zone_contents_set_gen_new_finished(contents_copy);
+
+ // set generation of all nodes to the old one
+ // now it is safe (no old nodes should be referenced)
+ ret = xfrin_fix_generation(contents_copy);
+ assert(ret == KNOT_EOK);
+
+ /*
+ * Now we may also set the generation back to 0 so that another
+ * update is possible.
+ */
+ knot_zone_contents_set_gen_old(contents_copy);
+
+ /*
+ * Wait until all readers finish reading
+ */
+ synchronize_rcu();
+
+ /*
+ * Delete all old and unused data.
+ */
+ xfrin_zone_contents_free(&old_contents);
+ xfrin_cleanup_update(&changes);
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/updates/xfr-in.h b/src/libknot/updates/xfr-in.h
new file mode 100644
index 0000000..8a7c64b
--- /dev/null
+++ b/src/libknot/updates/xfr-in.h
@@ -0,0 +1,184 @@
+/*!
+ * \file xfr-in.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief XFR client API.
+ *
+ * \addtogroup query_processing
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_XFR_IN_H_
+#define _KNOT_XFR_IN_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "dname.h"
+#include "zone/zone.h"
+#include "packet/packet.h"
+#include "nameserver/name-server.h"
+#include "updates/changesets.h"
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct xfrin_orphan_rrsig {
+ knot_rrset_t *rrsig;
+ struct xfrin_orphan_rrsig *next;
+} xfrin_orphan_rrsig_t;
+
+typedef struct xfrin_constructed_zone {
+ knot_zone_contents_t *contents;
+ xfrin_orphan_rrsig_t *rrsigs;
+} xfrin_constructed_zone_t;
+
+typedef enum xfrin_transfer_result {
+ XFRIN_RES_COMPLETE = 1,
+ XFRIN_RES_SOA_ONLY = 2,
+ XFRIN_RES_FALLBACK = 3
+} xfrin_transfer_result_t;
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Creates normal query for the given zone name and the SOA type.
+ *
+ * \param owner Zone owner.
+ * \param buffer Buffer to fill the message in.
+ * \param size In: available space in the buffer. Out: actual size of the
+ * message in bytes.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ESPACE
+ * \retval KNOT_ERROR
+ */
+int xfrin_create_soa_query(knot_dname_t *owner, knot_ns_xfr_t *xfr,
+ size_t *size);
+
+/*!
+ * \brief Checks if a zone transfer is required by comparing the zone's SOA with
+ * the one received from master server.
+ *
+ * \param zone Zone to check.
+ * \param soa_response Response to SOA query received from master server.
+ *
+ * \retval < 0 if an error occured.
+ * \retval 1 if the transfer is needed.
+ * \retval 0 if the transfer is not needed.
+ */
+int xfrin_transfer_needed(const knot_zone_contents_t *zone,
+ knot_packet_t *soa_response);
+
+/*!
+ * \brief Creates normal query for the given zone name and the AXFR type.
+ *
+ * \param owner Zone owner.
+ * \param xfr Data structure holding important data for the query, namely
+ * pointer to the buffer for wireformat and TSIG data.
+ * \param size In: available space in the buffer. Out: actual size of the
+ * message in bytes.
+ * \param use_tsig If TSIG should be used.
+ *
+ * \todo Parameter use_tsig probably not needed.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ESPACE
+ * \retval KNOT_ERROR
+ */
+int xfrin_create_axfr_query(knot_dname_t *owner, knot_ns_xfr_t *xfr,
+ size_t *size, int use_tsig);
+
+/*!
+ * \brief Creates normal query for the given zone name and the IXFR type.
+ *
+ * \param zone Zone contents.
+ * \param buffer Buffer to fill the message in.
+ * \param size In: available space in the buffer. Out: actual size of the
+ * message in bytes.
+ * \param use_tsig If TSIG should be used.
+ *
+ * \todo Parameter use_tsig probably not needed.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ESPACE
+ * \retval KNOT_ERROR
+ */
+int xfrin_create_ixfr_query(const knot_zone_contents_t *zone,
+ knot_ns_xfr_t *xfr, size_t *size, int use_tsig);
+
+/*!
+ * \brief Processes the newly created transferred zone.
+ *
+ * \param nameserver Name server to update.
+ * \param zone Zone build from transfer.
+ *
+ * \retval KNOT_ENOTSUP
+ */
+int xfrin_zone_transferred(knot_nameserver_t *nameserver,
+ knot_zone_contents_t *zone);
+
+/*!
+ * \brief Processes one incoming packet of AXFR transfer by updating the given
+ * zone.
+ *
+ * \param pkt Incoming packet in wire format.
+ * \param size Size of the packet in bytes.
+ * \param zone Zone being built. If there is no such zone (i.e. this is the
+ * first packet, \a *zone may be set to NULL, in which case a new
+ * zone structure is created).
+ *
+ * \retval KNOT_EOK
+ *
+ * \todo Refactor!!!
+ */
+int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size,
+ xfrin_constructed_zone_t **zone*/
+ knot_ns_xfr_t *xfr);
+
+/*!
+ * \brief Destroys the whole changesets structure.
+ *
+ * Frees all RRSets present in the changesets and all their data. Also frees
+ * the changesets structure and sets the parameter to NULL.
+ *
+ * \param changesets Changesets to destroy.
+ */
+void xfrin_free_changesets(knot_changesets_t **changesets);
+
+/*!
+ * \brief Parses IXFR reply packet and fills in the changesets structure.
+ *
+ * \param pkt Packet containing the IXFR reply in wire format.
+ * \param size Size of the packet in bytes.
+ * \param changesets Changesets to be filled in.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
+ * \retval KNOT_EMALF
+ * \retval KNOT_ENOMEM
+ */
+int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr/*const uint8_t *pkt, size_t size,
+ knot_changesets_t **changesets*/);
+
+int xfrin_apply_changesets_to_zone(knot_zone_t *zone,
+ knot_changesets_t *chsets);
+
+#endif /* _KNOTXFR_IN_H_ */
+
+/*! @} */
diff --git a/src/libknot/util/debug.c b/src/libknot/util/debug.c
new file mode 100644
index 0000000..0ca67c9
--- /dev/null
+++ b/src/libknot/util/debug.c
@@ -0,0 +1,233 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "util/utils.h"
+#include "util/debug.h"
+#include "libknot.h"
+#include "common/print.h"
+
+void knot_rdata_dump(knot_rdata_t *rdata, uint32_t type, char loaded_zone)
+{
+#if defined(KNOT_ZONE_DEBUG) || defined(KNOT_RDATA_DEBUG)
+ fprintf(stderr, " ------- RDATA -------\n");
+ if (rdata == NULL) {
+ fprintf(stderr, " There are no rdata in this RRset!\n");
+ fprintf(stderr, " ------- RDATA -------\n");
+ return;
+ }
+ knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(type);
+ assert(desc != NULL);
+ char *name;
+
+ for (int i = 0; i < rdata->count; i++) {
+ if (rdata->items[i].raw_data == NULL) {
+ continue;
+ }
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) {
+ assert(rdata->items[i].dname != NULL);
+ name = knot_dname_to_str(rdata->items[i].dname);
+ fprintf(stderr, " DNAME: %d: %s\n",
+ i, name);
+ free(name);
+ if (loaded_zone) {
+ if (rdata->items[i].dname->node) {
+ name =
+ knot_dname_to_str(rdata->items[i].dname->node->owner);
+ fprintf(stderr, " Has node owner: %s\n", name);
+ free(name);
+ } else {
+ fprintf(stderr, " No node set\n");
+ }
+ }
+ fprintf(stderr, " labels: ");
+ hex_print((char *)rdata->items[i].dname->labels,
+ rdata->items[i].dname->label_count);
+
+ } else {
+ assert(rdata->items[i].raw_data != NULL);
+ fprintf(stderr, " %d: raw_data: length: %d\n", i,
+ *(rdata->items[i].raw_data));
+ fprintf(stderr, " ");
+ hex_print(((char *)(
+ rdata->items[i].raw_data + 1)),
+ rdata->items[i].raw_data[0]);
+ }
+ }
+ fprintf(stderr, " ------- RDATA -------\n");
+#endif
+}
+
+void knot_rrset_dump(const knot_rrset_t *rrset, char loaded_zone)
+{
+#if defined(KNOT_ZONE_DEBUG) || defined(KNOT_RRSET_DEBUG)
+ fprintf(stderr, " ------- RRSET -------\n");
+ fprintf(stderr, " %p\n", rrset);
+ if (!rrset) {
+ return;
+ }
+ char *name = knot_dname_to_str(rrset->owner);
+ fprintf(stderr, " owner: %s\n", name);
+ free(name);
+ fprintf(stderr, " type: %s\n", knot_rrtype_to_string(rrset->type));
+ fprintf(stderr, " class: %d\n", rrset->rclass);
+ fprintf(stderr, " ttl: %d\n", rrset->ttl);
+
+ fprintf(stderr, " RRSIGs:\n");
+ if (rrset->rrsigs != NULL) {
+ knot_rrset_dump(rrset->rrsigs, loaded_zone);
+ } else {
+ fprintf(stderr, " none\n");
+ }
+
+ if (rrset->rdata == NULL) {
+ fprintf(stderr, " NO RDATA!\n");
+ fprintf(stderr, " ------- RRSET -------\n");
+ return;
+ }
+
+ fprintf(stderr, " rdata count: %d\n", rrset->rdata->count);
+ knot_rdata_t *tmp = rrset->rdata;
+
+ while (tmp->next != rrset->rdata && tmp->next != NULL) {
+ knot_rdata_dump(tmp, rrset->type, loaded_zone);
+ tmp = tmp->next;
+ }
+
+ knot_rdata_dump(tmp, rrset->type, loaded_zone);
+
+ fprintf(stderr, " ------- RRSET -------\n");
+#endif
+}
+
+void knot_node_dump(knot_node_t *node, void *loaded_zone)
+{
+#if defined(KNOT_ZONE_DEBUG) || defined(KNOT_NODE_DEBUG)
+ //char loaded_zone = *((char*) data);
+ char *name;
+
+ fprintf(stderr, "------- NODE --------\n");
+ name = knot_dname_to_str(node->owner);
+ fprintf(stderr, "owner: %s\n", name);
+ free(name);
+ fprintf(stderr, "labels: ");
+ hex_print((char *)node->owner->labels, node->owner->label_count);
+ fprintf(stderr, "node: %p\n", node);
+ fprintf(stderr, "node (in node's owner): %p\n", node->owner->node);
+ if (loaded_zone && node->prev != NULL) {
+ name = knot_dname_to_str(node->prev->owner);
+ fprintf(stderr, "previous node: %s\n", name);
+ free(name);
+ }
+
+ if (knot_node_is_deleg_point(node)) {
+ fprintf(stderr, "delegation point\n");
+ }
+
+ if (knot_node_is_non_auth(node)) {
+ fprintf(stderr, "non-authoritative node\n");
+ }
+
+ if (node->parent != NULL) {
+ /*! \todo This causes segfault when parent was free'd,
+ * e.g. when applying changesets.
+ */
+ name = knot_dname_to_str(node->parent->owner);
+ fprintf(stderr, "parent: %s\n", name);
+ free(name);
+ } else {
+ fprintf(stderr, "no parent\n");
+ }
+
+ if (node->prev != NULL) {
+ fprintf(stderr, "previous node: %p\n", node->prev);
+ /*! \todo This causes segfault when prev was free'd,
+ * e.g. when applying changesets.
+ */
+ name = knot_dname_to_str(node->prev->owner);
+ fprintf(stderr, "previous node: %s\n", name);
+ free(name);
+ } else {
+ fprintf(stderr, "previous node: none\n");
+ }
+
+ knot_rrset_t **rrsets = knot_node_get_rrsets(node);
+
+ fprintf(stderr, "Wildcard child: ");
+
+ if (node->wildcard_child != NULL) {
+ /*! \todo This causes segfault when wildcard child was free'd,
+ * e.g. when applying changesets.
+ */
+ name = knot_dname_to_str(node->wildcard_child->owner);
+ fprintf(stderr, "%s\n", name);
+ free(name);
+ } else {
+ fprintf(stderr, "none\n");
+ }
+
+ fprintf(stderr, "NSEC3 node: ");
+
+ if (node->nsec3_node != NULL) {
+ /*! \todo This causes segfault when nsec3_node was free'd,
+ * e.g. when applying changesets.
+ */
+ name = knot_dname_to_str(node->nsec3_node->owner);
+ fprintf(stderr, "%s\n", name);
+ free(name);
+ } else {
+ fprintf(stderr, "none\n");
+ }
+
+ fprintf(stderr, "RRSet count: %d\n", node->rrset_count);
+
+ for (int i = 0; i < node->rrset_count; i++) {
+ knot_rrset_dump(rrsets[i], (int) loaded_zone);
+ }
+ free(rrsets);
+ //assert(node->owner->node == node);
+ fprintf(stderr, "------- NODE --------\n");
+#endif
+}
+
+void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone)
+{
+#if defined(KNOT_ZONE_DEBUG)
+ if (!zone) {
+ fprintf(stderr, "------- STUB ZONE --------\n");
+ return;
+ }
+
+ fprintf(stderr, "------- ZONE --------\n");
+
+ knot_zone_contents_tree_apply_inorder(zone, knot_node_dump, (void *)&loaded_zone);
+
+ fprintf(stderr, "------- ZONE --------\n");
+
+ fprintf(stderr, "------- NSEC 3 tree -\n");
+
+ knot_zone_contents_nsec3_apply_inorder(zone, knot_node_dump, (void *)&loaded_zone);
+
+ fprintf(stderr, "------- NSEC 3 tree -\n");
+#endif
+}
diff --git a/src/libknot/util/debug.h b/src/libknot/util/debug.h
new file mode 100644
index 0000000..2f9f5fd
--- /dev/null
+++ b/src/libknot/util/debug.h
@@ -0,0 +1,755 @@
+/*!
+ * \file debug.h
+ *
+ * \author Jan Kadlec <jan.kadlec.@nic.cz>
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ *
+ * \brief Functions for debug output of structures.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_DEBUG_H_
+#define _KNOT_DEBUG_H_
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "config.h" /* autoconf generated */
+
+#include "rdata.h"
+#include "rrset.h"
+#include "zone/node.h"
+#include "zone/zone.h"
+#include "util/utils.h"
+#include "common/print.h"
+
+/*
+ * Debug macros
+ */
+/*! \todo Set these during configure. */
+//#define KNOT_ZONE_DEBUG
+//#define KNOT_RESPONSE_DEBUG
+//#define KNOT_ZONEDB_DEBUG
+//#define KNOT_DNAME_DEBUG
+//#define KNOT_NODE_DEBUG
+//#define KNOT_PACKET_DEBUG
+//#define KNOT_EDNS_DEBUG
+//#define KNOT_RRSET_DEBUG
+//#define KNOT_RDATA_DEBUG
+//#define KNOT_NSEC3_DEBUG
+//#define CUCKOO_DEBUG
+//#define CUCKOO_DEBUG_HASH
+//#define KNOT_NS_DEBUG
+//#define KNOT_XFRIN_DEBUG
+//#define KNOT_DDNS_DEBUG
+//#define KNOT_TSIG_DEBUG
+
+/*!
+ * \brief Dumps RDATA of the given type.
+ *
+ * This function is empty if neither KNOT_ZONE_DEBUG nor KNOT_RDATA_DEBUG
+ * is defined.
+ *
+ * \param rdata RDATA to dump.
+ * \param type Type of the RDATA (needed to properly parse the RDATA).
+ * \param loaded_zone Set to <> 0 if the RDATA is part of a zone loaded into
+ * the server. Set to 0 otherwise.
+ */
+void knot_rdata_dump(knot_rdata_t *rdata, uint32_t type, char loaded_zone);
+
+/*!
+ * \brief Dumps RRSet.
+ *
+ * This function is empty if neither KNOT_ZONE_DEBUG nor KNOT_RRSET_DEBUG
+ * is defined.
+ *
+ * \param rrset RRSet to dump.
+ * \param loaded_zone Set to <> 0 if the RRSet is part of a zone loaded into
+ * the server. Set to 0 otherwise.
+ */
+void knot_rrset_dump(const knot_rrset_t *rrset, char loaded_zone);
+
+/*!
+ * \brief Dumps zone node.
+ *
+ * This function is empty if neither KNOT_ZONE_DEBUG nor KNOT_NODE_DEBUG
+ * is defined.
+ *
+ * \param node Node to dump.
+ * \param loaded_zone Set to <> 0 if the node is part of a zone loaded into
+ * the server. Set to 0 otherwise.
+ */
+void knot_node_dump(knot_node_t *node, void *loaded_zone);
+
+/*!
+ * \brief Dumps the whole zone.
+ *
+ * This function is empty if KNOT_ZONE_DEBUG is not defined.
+ *
+ * \param zone Zone to dump.
+ * \param loaded_zone Set to <> 0 if the node is part of a zone loaded into
+ * the server. Set to 0 otherwise.
+ */
+void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone);
+
+/******************************************************************************/
+
+#ifdef KNOT_NS_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_ns(msg...) fprintf(stderr, msg)
+#define dbg_ns_hex(data, len) hex_print((data), (len))
+#define dbg_ns_exec(cmds) do { cmds } while (0)
+#else
+#define dbg_ns(msg...)
+#define dbg_ns_hex(data, len)
+#define dbg_ns_exec(cmds)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_ns_verb(msg...) fprintf(stderr, msg)
+#define dbg_ns_hex_verb(data, len) hex_print((data), (len))
+#define dbg_ns_exec_verb(cmds) do { cmds } while (0)
+#else
+#define dbg_ns_verb(msg...)
+#define dbg_ns_hex_verb(data, len)
+#define dbg_ns_exec_verb(cmds)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_ns_detail(msg...) fprintf(stderr, msg)
+#define dbg_ns_hex_detail(data, len) hex_print((data), (len))
+#define dbg_ns_exec_detail(cmds) do { cmds } while (0)
+#else
+#define dbg_ns_detail(msg...)
+#define dbg_ns_hex_detail(data, len)
+#define dbg_ns_exec_detail(cmds)
+#endif
+
+/* No messages. */
+#else
+#define dbg_ns(msg...)
+#define dbg_ns_hex(data, len)
+#define dbg_ns_exec(cmds)
+#define dbg_ns_verb(msg...)
+#define dbg_ns_hex_verb(data, len)
+#define dbg_ns_exec_verb(cmds)
+#define dbg_ns_detail(msg...)
+#define dbg_ns_hex_detail(data, len)
+#define dbg_ns_exec_detail(cmds)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_DNAME_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_dname(msg...) fprintf(stderr, msg)
+#define dbg_dname_hex(data, len) hex_print((data), (len))
+#define dbg_dname_exec(cmds) do { cmds } while (0)
+#else
+#define dbg_dname(msg...)
+#define dbg_dname_hex(data, len)
+#define dbg_dname_exec(cmds)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_dname_verb(msg...) fprintf(stderr, msg)
+#define dbg_dname_hex_verb(data, len) hex_print((data), (len))
+#define dbg_dname_exec_verb(cmds) do { cmds } while (0)
+#else
+#define dbg_dname_verb(msg...)
+#define dbg_dname_hex_verb(data, len)
+#define dbg_dname_exec_verb(cmds)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_dname_detail(msg...) fprintf(stderr, msg)
+#define dbg_dname_hex_detail(data, len) hex_print((data), (len))
+#define dbg_dname_exec_detail(cmds) do { cmds } while (0)
+#else
+#define dbg_dname_detail(msg...)
+#define dbg_dname_hex_detail(data, len)
+#define dbg_dname_exec_detail(cmds)
+#endif
+
+/* No messages. */
+#else
+#define dbg_dname(msg...)
+#define dbg_dname_hex(data, len)
+#define dbg_dname_exec(cmds)
+#define dbg_dname_verb(msg...)
+#define dbg_dname_hex_verb(data, len)
+#define dbg_dname_exec_verb(cmds)
+#define dbg_dname_detail(msg...)
+#define dbg_dname_hex_detail(data, len)
+#define dbg_dname_exec_detail(cmds)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_NODE_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_node(msg...) fprintf(stderr, msg)
+#define dbg_node_hex(data, len) hex_print((data), (len))
+#else
+#define dbg_node(msg...)
+#define dbg_node_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_node_verb(msg...) fprintf(stderr, msg)
+#define dbg_node_hex_verb(data, len) hex_print((data), (len))
+#else
+#define dbg_node_verb(msg...)
+#define dbg_node_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_node_detail(msg...) fprintf(stderr, msg)
+#define dbg_node_hex_detail(data, len) hex_print((data), (len))
+#else
+#define dbg_node_detail(msg...)
+#define dbg_node_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_node(msg...)
+#define dbg_node_hex(data, len)
+#define dbg_node_verb(msg...)
+#define dbg_node_hex_verb(data, len)
+#define dbg_node_detail(msg...)
+#define dbg_node_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_ZONE_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_zone(msg...) fprintf(stderr, msg)
+#define dbg_zone_hex(data, len) hex_print((data), (len))
+#define dbg_zone_exec(cmds) do { cmds } while (0)
+#else
+#define dbg_zone(msg...)
+#define dbg_zone_hex(data, len)
+#define dbg_zone_exec(cmds)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_zone_verb(msg...) fprintf(stderr, msg)
+#define dbg_zone_hex_verb(data, len) hex_print((data), (len))
+#define dbg_zone_exec_verb(cmds) do { cmds } while (0)
+#else
+#define dbg_zone_verb(msg...)
+#define dbg_zone_hex_verb(data, len)
+#define dbg_zone_exec_verb(cmds)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_zone_detail(msg...) fprintf(stderr, msg)
+#define dbg_zone_hex_detail(data, len) hex_print((data), (len))
+#define dbg_zone_exec_detail(cmds) do { cmds } while (0)
+#else
+#define dbg_zone_detail(msg...)
+#define dbg_zone_hex_detail(data, len)
+#define dbg_zone_exec_detail(cmds)
+#endif
+
+/* No messages. */
+#else
+#define dbg_zone(msg...)
+#define dbg_zone_hex(data, len)
+#define dbg_zone_exec(cmds)
+#define dbg_zone_verb(msg...)
+#define dbg_zone_hex_verb(data, len)
+#define dbg_zone_exec_verb(cmds)
+#define dbg_zone_detail(msg...)
+#define dbg_zone_hex_detail(data, len)
+#define dbg_zone_exec_detail(cmds)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_ZONEDB_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_zonedb(msg...) fprintf(stderr, msg)
+#define dbg_zonedb_hex(data, len) hex_print((data), (len))
+#define dbg_zonedb_exec(cmds) do { cmds } while (0)
+#else
+#define dbg_zonedb(msg...)
+#define dbg_zonedb_hex(data, len)
+#define dbg_zonedb_exec(cmds)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_zonedb_verb(msg...) fprintf(stderr, msg)
+#define dbg_zonedb_hex_verb(data, len) hex_print((data), (len))
+#define dbg_zonedb_exec_verb(cmds) do { cmds } while (0)
+#else
+#define dbg_zonedb_verb(msg...)
+#define dbg_zonedb_hex_verb(data, len)
+#define dbg_zonedb_exec_verb(cmds)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_zonedb_detail(msg...) fprintf(stderr, msg)
+#define dbg_zonedb_hex_detail(data, len) hex_print((data), (len))
+#define dbg_zonedb_exec_detail(cmds) do { cmds } while (0)
+#else
+#define dbg_zonedb_detail(msg...)
+#define dbg_zonedb_hex_detail(data, len)
+#define dbg_zonedb_exec_detail(cmds)
+#endif
+
+/* No messages. */
+#else
+#define dbg_zonedb(msg...)
+#define dbg_zonedb_hex(data, len)
+#define dbg_zonedb_exec(cmds)
+#define dbg_zonedb_verb(msg...)
+#define dbg_zonedb_hex_verb(data, len)
+#define dbg_zonedb_exec_verb(cmds)
+#define dbg_zonedb_detail(msg...)
+#define dbg_zonedb_hex_detail(data, len)
+#define dbg_zonedb_exec_detail(cmds)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_RESPONSE_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_response(msg...) fprintf(stderr, msg)
+#define dbg_response_hex(data, len) hex_print((data), (len))
+#define dbg_response_exec(cmds) do { cmds } while (0)
+#else
+#define dbg_response(msg...)
+#define dbg_response_hex(data, len)
+#define dbg_response_exec(cmds)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_response_verb(msg...) fprintf(stderr, msg)
+#define dbg_response_hex_verb(data, len) hex_print((data), (len))
+#define dbg_response_exec_verb(cmds) do { cmds } while (0)
+#else
+#define dbg_response_verb(msg...)
+#define dbg_response_hex_verb(data, len)
+#define dbg_response_exec_verb(cmds)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_response_detail(msg...) fprintf(stderr, msg)
+#define dbg_response_hex_detail(data, len) hex_print((data), (len))
+#define dbg_response_exec_detail(cmds) do { cmds } while (0)
+#else
+#define dbg_response_detail(msg...)
+#define dbg_response_hex_detail(data, len)
+#define dbg_response_exec_detail(cmds)
+#endif
+
+/* No messages. */
+#else
+#define dbg_response(msg...)
+#define dbg_response_hex(data, len)
+#define dbg_response_exec(cmds)
+#define dbg_response_verb(msg...)
+#define dbg_response_hex_verb(data, len)
+#define dbg_response_exec_verb(cmds)
+#define dbg_response_detail(msg...)
+#define dbg_response_hex_detail(data, len)
+#define dbg_response_exec_detail(cmds)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_PACKET_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_packet(msg...) fprintf(stderr, msg)
+#define dbg_packet_hex(data, len) hex_print((data), (len))
+#define dbg_packet_exec(cmds) do { cmds } while (0)
+#else
+#define dbg_packet(msg...)
+#define dbg_packet_hex(data, len)
+#define dbg_packet_exec(cmds)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_packet_verb(msg...) fprintf(stderr, msg)
+#define dbg_packet_hex_verb(data, len) hex_print((data), (len))
+#define dbg_packet_exec_verb(cmds) do { cmds } while (0)
+#else
+#define dbg_packet_verb(msg...)
+#define dbg_packet_hex_verb(data, len)
+#define dbg_packet_exec_verb(cmds)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_packet_detail(msg...) fprintf(stderr, msg)
+#define dbg_packet_hex_detail(data, len) hex_print((data), (len))
+#define dbg_packet_exec_detail(cmds) do { cmds } while (0)
+#else
+#define dbg_packet_detail(msg...)
+#define dbg_packet_hex_detail(data, len)
+#define dbg_packet_exec_detail(cmds)
+#endif
+
+/* No messages. */
+#else
+#define dbg_packet(msg...)
+#define dbg_packet_hex(data, len)
+#define dbg_packet_exec(cmds)
+#define dbg_packet_verb(msg...)
+#define dbg_packet_hex_verb(data, len)
+#define dbg_packet_exec_verb(cmds)
+#define dbg_packet_detail(msg...)
+#define dbg_packet_hex_detail(data, len)
+#define dbg_packet_exec_detail(cmds)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_EDNS_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_edns(msg...) fprintf(stderr, msg)
+#define dbg_edns_hex(data, len) hex_print((data), (len))
+#else
+#define dbg_edns(msg...)
+#define dbg_edns_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_edns_verb(msg...) fprintf(stderr, msg)
+#define dbg_edns_hex_verb(data, len) hex_print((data), (len))
+#else
+#define dbg_edns_verb(msg...)
+#define dbg_edns_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_edns_detail(msg...) fprintf(stderr, msg)
+#define dbg_edns_hex_detail(data, len) hex_print((data), (len))
+#else
+#define dbg_edns_detail(msg...)
+#define dbg_edns_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_edns(msg...)
+#define dbg_edns_hex(data, len)
+#define dbg_edns_verb(msg...)
+#define dbg_edns_hex_verb(data, len)
+#define dbg_edns_detail(msg...)
+#define dbg_edns_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_NSEC3_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_nsec3(msg...) fprintf(stderr, msg)
+#define dbg_nsec3_hex(data, len) hex_print((data), (len))
+#else
+#define dbg_nsec3(msg...)
+#define dbg_nsec3_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_nsec3_verb(msg...) fprintf(stderr, msg)
+#define dbg_nsec3_hex_verb(data, len) hex_print((data), (len))
+#else
+#define dbg_nsec3_verb(msg...)
+#define dbg_nsec3_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_nsec3_detail(msg...) fprintf(stderr, msg)
+#define dbg_nsec3_hex_detail(data, len) hex_print((data), (len))
+#else
+#define dbg_nsec3_detail(msg...)
+#define dbg_nsec3_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_nsec3(msg...)
+#define dbg_nsec3_hex(data, len)
+#define dbg_nsec3_verb(msg...)
+#define dbg_nsec3_hex_verb(data, len)
+#define dbg_nsec3_detail(msg...)
+#define dbg_nsec3_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef CUCKOO_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_ck(msg...) fprintf(stderr, msg)
+#define dbg_ck_hex(data, len) hex_print((data), (len))
+#else
+#define dbg_ck(msg...)
+#define dbg_ck_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_ck_verb(msg...) fprintf(stderr, msg)
+#define dbg_ck_hex_verb(data, len) hex_print((data), (len))
+#else
+#define dbg_ck_verb(msg...)
+#define dbg_ck_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_ck_detail(msg...) fprintf(stderr, msg)
+#define dbg_ck_hex_detail(data, len) hex_print((data), (len))
+#else
+#define dbg_ck_detail(msg...)
+#define dbg_ck_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_ck(msg...)
+#define dbg_ck_hex(data, len)
+#define dbg_ck_verb(msg...)
+#define dbg_ck_hex_verb(data, len)
+#define dbg_ck_detail(msg...)
+#define dbg_ck_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef CUCKOO_DEBUG_HASH
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_ck_hash(msg...) fprintf(stderr, msg)
+#define dbg_ck_rehash(msg...) fprintf(stderr, msg)
+#define dbg_ck_hash_hex(data, len) hex_print((data), (len))
+#else
+#define dbg_ck_hash(msg...)
+#define dbg_ck_rehash(msg...)
+#define dbg_ck_hash_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_ck_hash_verb(msg...) fprintf(stderr, msg)
+#define dbg_ck_hash_hex_verb(data, len) hex_print((data), (len))
+#else
+#define dbg_ck_hash_verb(msg...)
+#define dbg_ck_hash_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_ck_hash_detail(msg...) fprintf(stderr, msg)
+#define dbg_ck_hash_hex_detail(data, len) hex_print((data), (len))
+#else
+#define dbg_ck_hash_detail(msg...)
+#define dbg_ck_hash_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_ck_hash(msg...)
+#define dbg_ck_rehash(msg...)
+#define dbg_ck_hash_hex(data, len)
+#define dbg_ck_hash_verb(msg...)
+#define dbg_ck_hash_hex_verb(data, len)
+#define dbg_ck_hash_detail(msg...)
+#define dbg_ck_hash_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_XFRIN_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_xfrin(msg...) fprintf(stderr, msg)
+#define dbg_xfrin_hex(data, len) hex_print((data), (len))
+#define dbg_xfrin_exec(cmds) do { cmds } while (0)
+#else
+#define dbg_xfrin(msg...)
+#define dbg_xfrin_hex(data, len)
+#define dbg_xfrin_exec(cmds)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_xfrin_verb(msg...) fprintf(stderr, msg)
+#define dbg_xfrin_hex_verb(data, len) hex_print((data), (len))
+#define dbg_xfrin_exec_verb(cmds) do { cmds } while (0)
+#else
+#define dbg_xfrin_verb(msg...)
+#define dbg_xfrin_hex_verb(data, len)
+#define dbg_xfrin_exec_verb(cmds)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_xfrin_detail(msg...) fprintf(stderr, msg)
+#define dbg_xfrin_hex_detail(data, len) hex_print((data), (len))
+#define dbg_xfrin_exec_detail(cmds) do { cmds } while (0)
+#else
+#define dbg_xfrin_detail(msg...)
+#define dbg_xfrin_hex_detail(data, len)
+#define dbg_xfrin_exec_detail(cmds)
+#endif
+
+/* No messages. */
+#else
+#define dbg_xfrin(msg...)
+#define dbg_xfrin_hex(data, len)
+#define dbg_xfrin_exec(cmds)
+#define dbg_xfrin_verb(msg...)
+#define dbg_xfrin_hex_verb(data, len)
+#define dbg_xfrin_exec_verb(cmds)
+#define dbg_xfrin_detail(msg...)
+#define dbg_xfrin_hex_detail(data, len)
+#define dbg_xfrin_exec_detail(cmds)
+#endif
+
+/******************************************************************************/
+
+#ifdef KNOT_DDNS_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_ddns(msg...) fprintf(stderr, msg)
+#define dbg_ddns_hex(data, len) hex_print((data), (len))
+#else
+#define dbg_ddns(msg...)
+#define dbg_ddns_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_ddns_verb(msg...) fprintf(stderr, msg)
+#define dbg_ddns_hex_verb(data, len) hex_print((data), (len))
+#else
+#define dbg_ddns_verb(msg...)
+#define dbg_ddns_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_ddns_detail(msg...) fprintf(stderr, msg)
+#define dbg_ddns_hex_detail(data, len) hex_print((data), (len))
+#else
+#define dbg_ddns_detail(msg...)
+#define dbg_ddns_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_ddns(msg...)
+#define dbg_ddns_hex(data, len)
+#define dbg_ddns_verb(msg...)
+#define dbg_ddns_hex_verb(data, len)
+#define dbg_ddns_detail(msg...)
+#define dbg_ddns_hex_detail(data, len)
+#endif
+
+#ifdef KNOT_TSIG_DEBUG
+
+/* Brief messages. */
+#ifdef DEBUG_ENABLE_BRIEF
+#define dbg_tsig(msg...) fprintf(stderr, msg)
+#define dbg_tsig_hex(data, len) hex_print((const char*)(data), (len))
+#else
+#define dbg_tsig(msg...)
+#define dbg_tsig_hex(data, len)
+#endif
+
+/* Verbose messages. */
+#ifdef DEBUG_ENABLE_VERBOSE
+#define dbg_tsig_verb(msg...) fprintf(stderr, msg)
+#define dbg_tsig_hex_verb(data, len) hex_print((const char*)(data), (len))
+#else
+#define dbg_tsig_verb(msg...)
+#define dbg_tsig_hex_verb(data, len)
+#endif
+
+/* Detail messages. */
+#ifdef DEBUG_ENABLE_DETAILS
+#define dbg_tsig_detail(msg...) fprintf(stderr, msg)
+#define dbg_tsig_hex_detail(data, len) hex_print((const char*)(data), (len))
+#else
+#define dbg_tsig_detail(msg...)
+#define dbg_tsig_hex_detail(data, len)
+#endif
+
+/* No messages. */
+#else
+#define dbg_tsig(msg...)
+#define dbg_tsig_hex(data, len)
+#define dbg_tsig_verb(msg...)
+#define dbg_tsig_hex_verb(data, len)
+#define dbg_tsig_detail(msg...)
+#define dbg_tsig_hex_detail(data, len)
+#endif
+
+/******************************************************************************/
+
+#endif /* _KNOT_DEBUG_H_ */
+
+/*! @} */
diff --git a/src/libknot/util/descriptor.c b/src/libknot/util/descriptor.c
new file mode 100644
index 0000000..fa94c24
--- /dev/null
+++ b/src/libknot/util/descriptor.c
@@ -0,0 +1,501 @@
+/*!
+ * \file descriptor.c
+ *
+ * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * most of the work by NLnet labs.
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \note Most of the constants and functions were taken from NSD's dns.c.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "libknot.h"
+
+enum desclen { KNOT_RRTYPE_DESCRIPTORS_LENGTH = 32770 }; // used to be 101
+
+/*!
+ * \brief Table for linking RR class constants to their textual representation.
+ */
+static knot_lookup_table_t dns_rrclasses[] = {
+ { KNOT_CLASS_IN, "IN" }, /* the Internet */
+ { KNOT_CLASS_CS, "CS" }, /* the CSNET class (Obsolete) */
+ { KNOT_CLASS_CH, "CH" }, /* the CHAOS class */
+ { KNOT_CLASS_HS, "HS" }, /* Hesiod */
+ { 0, NULL }
+};
+
+/*! \brief RR type descriptors. */
+static knot_rrtype_descriptor_t
+ knot_rrtype_descriptors[KNOT_RRTYPE_DESCRIPTORS_LENGTH] = {
+ /* 0 */
+ { 0, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 1 */
+ { KNOT_RRTYPE_A, "A", 1, { KNOT_RDATA_WF_A }, { KNOT_RDATA_ZF_A }, true },
+ /* 2 */
+ { KNOT_RRTYPE_NS, "NS", 1,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true },
+ /* 3 */
+ { KNOT_RRTYPE_MD, "MD", 1,
+ { KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true },
+ /* 4 */
+ { KNOT_RRTYPE_MF, "MF", 1,
+ { KNOT_RDATA_WF_UNCOMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true },
+ /* 5 */
+ { KNOT_RRTYPE_CNAME, "CNAME", 1,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true },
+ /* 6 */
+ { KNOT_RRTYPE_SOA, "SOA", 7,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME, KNOT_RDATA_WF_COMPRESSED_DNAME,
+ KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG,
+ KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG },
+ { KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_PERIOD, KNOT_RDATA_ZF_PERIOD,
+ KNOT_RDATA_ZF_PERIOD, KNOT_RDATA_ZF_PERIOD, KNOT_RDATA_ZF_PERIOD },
+ true },
+ /* 7 */
+ { KNOT_RRTYPE_MB, "MB", 1,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true },
+ /* 8 */
+ { KNOT_RRTYPE_MG, "MG", 1,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true },
+ /* 9 */
+ { KNOT_RRTYPE_MR, "MR", 1,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME }, { KNOT_RDATA_ZF_DNAME }, true },
+ /* 10 */
+ { KNOT_RRTYPE_NULL, NULL, 1,
+ { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 11 */
+ { KNOT_RRTYPE_WKS, "WKS", 2,
+ { KNOT_RDATA_WF_A, KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_A, KNOT_RDATA_ZF_SERVICES }, true },
+ /* 12 */
+ { KNOT_RRTYPE_PTR, "PTR", 1,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_DNAME }, true },
+ /* 13 */
+ { KNOT_RRTYPE_HINFO, "HINFO", 2,
+ { KNOT_RDATA_WF_TEXT_SINGLE, KNOT_RDATA_WF_TEXT_SINGLE },
+ { KNOT_RDATA_ZF_TEXT, KNOT_RDATA_ZF_TEXT }, true },
+ /* 14 */
+ { KNOT_RRTYPE_MINFO, "MINFO", 2,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME,
+ KNOT_RDATA_WF_COMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_DNAME }, true },
+ /* 15 */
+ { KNOT_RRTYPE_MX, "MX", 2,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_COMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, true },
+ /* 16 */ /* This is obscure, but I guess there's no other way */
+ { KNOT_RRTYPE_TXT, "TXT", 1,
+ { KNOT_RDATA_WF_TEXT },
+ { KNOT_RDATA_ZF_TEXT },
+ false },
+ /* 17 */
+ { KNOT_RRTYPE_RP, "RP", 2,
+ { KNOT_RDATA_WF_COMPRESSED_DNAME,
+ KNOT_RDATA_WF_COMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_DNAME }, true },
+ /* 18 */
+ { KNOT_RRTYPE_AFSDB, "AFSDB", 2,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_COMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, true },
+ /* 19 */
+ { KNOT_RRTYPE_X25, "X25", 1,
+ { KNOT_RDATA_WF_TEXT_SINGLE },
+ { KNOT_RDATA_ZF_TEXT }, true },
+ /* 20 */
+ { KNOT_RRTYPE_ISDN, "ISDN", 2,
+ { KNOT_RDATA_WF_TEXT_SINGLE, KNOT_RDATA_WF_TEXT_SINGLE },
+ { KNOT_RDATA_ZF_TEXT, KNOT_RDATA_ZF_TEXT }, false },
+ /* 21 */
+ { KNOT_RRTYPE_RT, "RT", 2,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_COMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, true },
+ /* 22 */
+ { KNOT_RRTYPE_NSAP, "NSAP", 1,
+ { KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_NSAP }, true },
+ /* 23 */
+ { 23, NULL, 1, { KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 24 */
+ { KNOT_RRTYPE_SIG, "SIG", 9,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BYTE,
+ KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG,
+ KNOT_RDATA_WF_SHORT,KNOT_RDATA_WF_UNCOMPRESSED_DNAME,
+ KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_RRTYPE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_PERIOD,
+ KNOT_RDATA_ZF_TIME, KNOT_RDATA_ZF_TIME, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME,
+ KNOT_RDATA_ZF_BASE64 },
+ true },
+ /* 25 */
+ { KNOT_RRTYPE_KEY, "KEY", 4,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE,
+ KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_ALGORITHM,
+ KNOT_RDATA_ZF_BASE64 }, true },
+ /* 26 */
+ { KNOT_RRTYPE_PX, "PX", 3,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_UNCOMPRESSED_DNAME,
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_DNAME }, true },
+ /* 27 */
+ { 27, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 28 */
+ { KNOT_RRTYPE_AAAA, "AAAA", 1,
+ { KNOT_RDATA_WF_AAAA },
+ { KNOT_RDATA_ZF_AAAA }, true },
+ /* 29 */
+ { KNOT_RRTYPE_LOC, "LOC", 1,
+ { KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_LOC }, true },
+ /* 30 */
+ { KNOT_RRTYPE_NXT, "NXT", 2,
+ { KNOT_RDATA_WF_UNCOMPRESSED_DNAME,
+ KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_DNAME, KNOT_RDATA_ZF_NXT }, true },
+ /* 31 */
+ { 31, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 32 */
+ { 32, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 33 */
+ { KNOT_RRTYPE_SRV, "SRV", 4,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_SHORT,
+ KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_UNCOMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME },
+ true },
+ /* 34 */
+ { 34, NULL, 1, { KNOT_RDATA_WF_BINARY }, { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 35 */
+ { KNOT_RRTYPE_NAPTR, "NAPTR", 6,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_TEXT_SINGLE,
+ KNOT_RDATA_WF_TEXT_SINGLE, KNOT_RDATA_WF_TEXT_SINGLE,
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_TEXT, KNOT_RDATA_ZF_TEXT,
+ KNOT_RDATA_ZF_TEXT, KNOT_RDATA_ZF_DNAME }, true },
+ /* 36 */
+ { KNOT_RRTYPE_KX, "KX", 2,
+ { KNOT_RDATA_WF_SHORT,
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_DNAME }, true },
+ /* 37 */
+ { KNOT_RRTYPE_CERT, "CERT", 4,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_SHORT,
+ KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_CERTIFICATE_TYPE, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_ALGORITHM,
+ KNOT_RDATA_ZF_BASE64 }, true },
+ /* 38 */
+ { KNOT_RRTYPE_A6, NULL, 1, { KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 39 */
+ { KNOT_RRTYPE_DNAME, "DNAME", 1,
+ { KNOT_RDATA_WF_UNCOMPRESSED_DNAME },
+ { KNOT_RDATA_ZF_DNAME }, true },
+ /* 40 */
+ { 40, NULL, 1, { KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 41 */
+ /* OPT has its parser token, but should never be in zone file... */
+ { KNOT_RRTYPE_OPT, "OPT", 1,
+ { KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_UNKNOWN }, true },
+ /* 42 */
+ { KNOT_RRTYPE_APL, "APL", 1,
+ { KNOT_RDATA_WF_APL },
+ { KNOT_RDATA_ZF_APL }, false },
+ /* 43 */
+ { KNOT_RRTYPE_DS, "DS", 4,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE,
+ KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_ALGORITHM, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_HEX }, true },
+ /* 44 */
+ { KNOT_RRTYPE_SSHFP, "SSHFP", 3,
+ { KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BYTE,
+ KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_HEX },
+ true },
+ /* 45 */
+ { KNOT_RRTYPE_IPSECKEY, "IPSECKEY", 5,
+ { KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BYTE,
+ KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_IPSECGATEWAY,
+ KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_IPSECGATEWAY,
+ KNOT_RDATA_ZF_BASE64 }, false },
+ /* 46 */
+ { KNOT_RRTYPE_RRSIG, "RRSIG", 9,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE,
+ KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_LONG,
+ KNOT_RDATA_WF_LONG, KNOT_RDATA_WF_LONG,
+ KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_LITERAL_DNAME,
+ KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_RRTYPE, KNOT_RDATA_ZF_ALGORITHM,
+ KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_PERIOD,
+ KNOT_RDATA_ZF_TIME, KNOT_RDATA_ZF_TIME,
+ KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_LITERAL_DNAME,
+ KNOT_RDATA_ZF_BASE64 }, true },
+ /* 47 */
+ { KNOT_RRTYPE_NSEC, "NSEC", 2,
+ { KNOT_RDATA_WF_LITERAL_DNAME, KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_LITERAL_DNAME, KNOT_RDATA_ZF_NSEC },
+ true },
+ /* 48 */
+ { KNOT_RRTYPE_DNSKEY, "DNSKEY", 4,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE,
+ KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_BYTE,
+ KNOT_RDATA_ZF_ALGORITHM, KNOT_RDATA_ZF_BASE64 }, true },
+ /* 49 */
+ { KNOT_RRTYPE_DHCID, "DHCID", 1, { KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_BASE64 }, true },
+ /* 50 */
+ { KNOT_RRTYPE_NSEC3, "NSEC3", 6,
+ { KNOT_RDATA_WF_BYTE, /* hash type */
+ KNOT_RDATA_WF_BYTE, /* flags */
+ KNOT_RDATA_WF_SHORT, /* iterations */
+ KNOT_RDATA_WF_BINARYWITHLENGTH, /* salt */
+ KNOT_RDATA_WF_BINARYWITHLENGTH, /* next hashed name */
+ KNOT_RDATA_WF_BINARY /* type bitmap */ },
+ { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_HEX_LEN,
+ KNOT_RDATA_ZF_BASE32, KNOT_RDATA_ZF_NSEC },
+ true },
+ /* 51 */
+ { KNOT_RRTYPE_NSEC3PARAM, "NSEC3PARAM", 4,
+ { KNOT_RDATA_WF_BYTE, /* hash type */
+ KNOT_RDATA_WF_BYTE, /* flags */
+ KNOT_RDATA_WF_SHORT, /* iterations */
+ KNOT_RDATA_WF_BINARYWITHLENGTH /* salt */ },
+ { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE,
+ KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_HEX_LEN }, true },
+ /* 52 */
+
+
+ /* In NSD they have indices between 52 and 99 filled with
+ unknown types. TODO add here if it's really needed? */
+ /* it is indeed needed, in rrtype_from_string */
+
+ /* There's a GNU extension that works like this: [first ... last] = value */
+
+ /* 99 */
+ [99] = { KNOT_RRTYPE_SPF, "SPF", 1,
+ { KNOT_RDATA_WF_TEXT },
+ { KNOT_RDATA_ZF_TEXT }, false },
+ /* TSIG pseudo RR. */
+ [250] = { KNOT_RRTYPE_TSIG, "TSIG", 7,
+ { KNOT_RDATA_WF_UNCOMPRESSED_DNAME, KNOT_RDATA_WF_UINT48,
+ KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BINARYWITHSHORT,
+ KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_SHORT,
+ KNOT_RDATA_WF_BINARYWITHSHORT },
+ /* Zoneformat not needed. */
+ {0, 0, 0, 0, 0}, true },
+ /* 32769 */
+ [32769] = { KNOT_RRTYPE_DLV, "DLV", 4,
+ { KNOT_RDATA_WF_SHORT, KNOT_RDATA_WF_BYTE,
+ KNOT_RDATA_WF_BYTE, KNOT_RDATA_WF_BINARY },
+ { KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_ALGORITHM, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_HEX },
+ true },
+};
+
+knot_rrtype_descriptor_t *knot_rrtype_descriptor_by_type(uint16_t type)
+{
+ if (type < KNOT_RRTYPE_LAST + 1) {
+ return &knot_rrtype_descriptors[type];
+ } else if (type == KNOT_RRTYPE_DLV) {
+ return &knot_rrtype_descriptors[KNOT_RRTYPE_DLV];
+ }
+ return &knot_rrtype_descriptors[0];
+}
+
+/* I see a lot of potential here to speed up zone parsing - this is O(n) *
+ * could be better */
+knot_rrtype_descriptor_t *knot_rrtype_descriptor_by_name(const char *name)
+{
+ int i;
+
+ for (i = 0; i < KNOT_RRTYPE_DLV + 1; ++i) {
+ if (knot_rrtype_descriptors[i].name &&
+ strcasecmp(knot_rrtype_descriptors[i].name, name) == 0) {
+ return &knot_rrtype_descriptors[i];
+ }
+ }
+
+ if (knot_rrtype_descriptors[KNOT_RRTYPE_DLV].name &&
+ strcasecmp(knot_rrtype_descriptors[KNOT_RRTYPE_DLV].name,
+ name) == 0) {
+ return &knot_rrtype_descriptors[KNOT_RRTYPE_DLV];
+ }
+
+ return NULL;
+}
+
+const char *knot_rrtype_to_string(uint16_t rrtype)
+{
+ static char buf[20];
+ knot_rrtype_descriptor_t *descriptor =
+ knot_rrtype_descriptor_by_type(rrtype);
+ if (descriptor->name) {
+ return descriptor->name;
+ } else {
+ snprintf(buf, sizeof(buf), "TYPE%d", (int) rrtype);
+ return buf;
+ }
+}
+
+uint16_t knot_rrtype_from_string(const char *name)
+{
+ char *end;
+ long rrtype;
+ knot_rrtype_descriptor_t *entry;
+
+ entry = knot_rrtype_descriptor_by_name(name);
+ if (entry) {
+ return entry->type;
+ }
+
+ if (strlen(name) < 5) {
+ return 0;
+ }
+
+ if (strncasecmp(name, "TYPE", 4) != 0) {
+ return 0;
+ }
+
+ if (!isdigit((int)name[4])) {
+ return 0;
+ }
+
+ /* The rest from the string must be a number. */
+ rrtype = strtol(name + 4, &end, 10);
+ if (*end != '\0') {
+ return 0;
+ }
+ if (rrtype < 0 || rrtype > 65535L) {
+ return 0;
+ }
+
+ return (uint16_t) rrtype;
+}
+
+const char *knot_rrclass_to_string(uint16_t rrclass)
+{
+ static char buf[20];
+ knot_lookup_table_t *entry = knot_lookup_by_id(dns_rrclasses,
+ rrclass);
+ if (entry) {
+ assert(strlen(entry->name) < sizeof(buf));
+ knot_strlcpy(buf, entry->name, sizeof(buf));
+ } else {
+ snprintf(buf, sizeof(buf), "CLASS%d", (int) rrclass);
+ }
+ return buf;
+}
+
+uint16_t knot_rrclass_from_string(const char *name)
+{
+ char *end;
+ long rrclass;
+ knot_lookup_table_t *entry;
+
+ entry = knot_lookup_by_name(dns_rrclasses, name);
+ if (entry) {
+ return (uint16_t) entry->id;
+ }
+
+ if (strlen(name) < 6) {
+ return 0;
+ }
+
+ if (strncasecmp(name, "CLASS", 5) != 0) {
+ return 0;
+ }
+
+ if (!isdigit((int)name[5])) {
+ return 0;
+ }
+
+ // The rest from the string must be a number.
+ rrclass = strtol(name + 5, &end, 10);
+ if (*end != '\0') {
+ return 0;
+ }
+ if (rrclass < 0 || rrclass > 65535L) {
+ return 0;
+ }
+
+ return (uint16_t) rrclass;
+}
+
+size_t knot_wireformat_size(unsigned int wire_type)
+{
+ switch(wire_type) {
+ case KNOT_RDATA_WF_BYTE:
+ return 1;
+ break;
+ case KNOT_RDATA_WF_SHORT:
+ return 2;
+ break;
+ case KNOT_RDATA_WF_LONG:
+ return 4;
+ break;
+ case KNOT_RDATA_WF_A:
+ return 4;
+ break;
+ default: /* unknown size */
+ return 0;
+ break;
+ } /* switch */
+}
+
+int knot_rrtype_is_metatype(uint16_t type)
+{
+ /*! \todo Check if there are some other metatypes. */
+ return (type == KNOT_RRTYPE_ANY
+ || type == KNOT_RRTYPE_AXFR
+ || type == KNOT_RRTYPE_IXFR
+ || type == KNOT_RRTYPE_MAILA
+ || type == KNOT_RRTYPE_MAILB
+ || type == KNOT_RRTYPE_OPT);
+}
+
diff --git a/src/libknot/util/descriptor.h b/src/libknot/util/descriptor.h
new file mode 100644
index 0000000..10d3d20
--- /dev/null
+++ b/src/libknot/util/descriptor.h
@@ -0,0 +1,332 @@
+/*!
+ * \file descriptor.h
+ *
+ * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * most of the work by NLnet Labs.
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \note Most of the constants and functions were taken from NSD's dns.h.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KNOT_DESCRIPTOR_H_
+#define _KNOT_DESCRIPTOR_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+enum knot_mxrdtln {
+ /*! \brief Maximum items in RDATA wireformat. */
+ KNOT_MAX_RDATA_ITEMS = 64,
+ /*! \brief Maximum size of one item in RDATA wireformat. */
+ KNOT_MAX_RDATA_ITEM_SIZE = 65534,
+ /*! \brief Maximum wire size of one RDATA. */
+ KNOT_MAX_RDATA_WIRE_SIZE =
+ KNOT_MAX_RDATA_ITEMS * KNOT_MAX_RDATA_ITEM_SIZE
+};
+
+typedef enum knot_mxrdtln knot_mxrdtln_t;
+//#define MAXRDATALEN 64
+
+/* 64 is in NSD. Seems a little too much, but I'd say it's not a real issue. */
+
+/*!
+ * \brief Resource record class codes.
+ */
+enum knot_rr_class {
+ KNOT_CLASS_IN = 1,
+ KNOT_CLASS_CS,
+ KNOT_CLASS_CH,
+ KNOT_CLASS_HS,
+ KNOT_CLASS_NONE = 254,
+ KNOT_CLASS_ANY = 255
+};
+
+typedef enum knot_rr_class knot_rr_class_t;
+
+/*!
+ * \brief Resource record type constants.
+ * \todo Not all indices can be used for indexing.
+ */
+enum knot_rr_type {
+ KNOT_RRTYPE_UNKNOWN, /*!< 0 - an unknown type */
+ KNOT_RRTYPE_A, /*!< 1 - a host address */
+ KNOT_RRTYPE_NS, /*!< 2 - an authoritative name server */
+ KNOT_RRTYPE_MD, /*!< 3 - a mail destination (Obsolete - use MX) */
+ KNOT_RRTYPE_MF, /*!< 4 - a mail forwarder (Obsolete - use MX) */
+ KNOT_RRTYPE_CNAME, /*!< 5 - the canonical name for an alias */
+ KNOT_RRTYPE_SOA, /*!< 6 - marks the start of a zone of authority */
+ KNOT_RRTYPE_MB, /*!< 7 - a mailbox domain name (EXPERIMENTAL) */
+ KNOT_RRTYPE_MG, /*!< 8 - a mail group member (EXPERIMENTAL) */
+ KNOT_RRTYPE_MR, /*!< 9 - a mail rename domain name (EXPERIMENTAL) */
+ KNOT_RRTYPE_NULL, /*!< 10 - a null RR (EXPERIMENTAL) */
+ KNOT_RRTYPE_WKS, /*!< 11 - a well known service description */
+ KNOT_RRTYPE_PTR, /*!< 12 - a domain name pointer */
+ KNOT_RRTYPE_HINFO, /*!< 13 - host information */
+ KNOT_RRTYPE_MINFO, /*!< 14 - mailbox or mail list information */
+ KNOT_RRTYPE_MX, /*!< 15 - mail exchange */
+ KNOT_RRTYPE_TXT, /*!< 16 - text strings */
+ KNOT_RRTYPE_RP, /*!< 17 - RFC1183 */
+ KNOT_RRTYPE_AFSDB, /*!< 18 - RFC1183 */
+ KNOT_RRTYPE_X25, /*!< 19 - RFC1183 */
+ KNOT_RRTYPE_ISDN, /*!< 20 - RFC1183 */
+ KNOT_RRTYPE_RT, /*!< 21 - RFC1183 */
+ KNOT_RRTYPE_NSAP, /*!< 22 - RFC1706 */
+
+ KNOT_RRTYPE_SIG = 24, /*!< 24 - 2535typecode */
+ KNOT_RRTYPE_KEY, /*!< 25 - 2535typecode */
+ KNOT_RRTYPE_PX, /*!< 26 - RFC2163 */
+
+ KNOT_RRTYPE_AAAA = 28, /*!< 28 - ipv6 address */
+ KNOT_RRTYPE_LOC, /*!< 29 - LOC record RFC1876 */
+ KNOT_RRTYPE_NXT, /*!< 30 - 2535typecode */
+
+ KNOT_RRTYPE_SRV = 33, /*!< 33 - SRV record RFC2782 */
+
+ KNOT_RRTYPE_NAPTR = 35, /*!< 35 - RFC2915 */
+ KNOT_RRTYPE_KX, /*!< 36 - RFC2230 Key Exchange Delegation Record */
+ KNOT_RRTYPE_CERT, /*!< 37 - RFC2538 */
+ KNOT_RRTYPE_A6, /*!< 38 - RFC2874 */
+ KNOT_RRTYPE_DNAME, /*!< 39 - RFC2672 */
+
+ KNOT_RRTYPE_OPT = 41, /*!< 41 - Pseudo OPT record... */
+ KNOT_RRTYPE_APL, /*!< 42 - RFC3123 */
+ KNOT_RRTYPE_DS, /*!< 43 - RFC 4033, 4034, and 4035 */
+ KNOT_RRTYPE_SSHFP, /*!< 44 - SSH Key Fingerprint */
+ KNOT_RRTYPE_IPSECKEY, /*!< 45 - public key for ipsec use. RFC 4025 */
+ KNOT_RRTYPE_RRSIG, /*!< 46 - RFC 4033, 4034, and 4035 */
+ KNOT_RRTYPE_NSEC, /*!< 47 - RFC 4033, 4034, and 4035 */
+ KNOT_RRTYPE_DNSKEY, /*!< 48 - RFC 4033, 4034, and 4035 */
+ KNOT_RRTYPE_DHCID, /*!< 49 - RFC4701 DHCP information */
+ /*!
+ * \brief 50 - NSEC3, secure denial, prevents zonewalking
+ */
+ KNOT_RRTYPE_NSEC3,
+ /*!
+ * \brief 51 - NSEC3PARAM at zone apex nsec3 parameters
+ */
+ KNOT_RRTYPE_NSEC3PARAM,
+
+ /* TODO consider some better way of doing this, indices too high */
+
+ KNOT_RRTYPE_SPF = 99, /*!< RFC 4408 */
+
+ // not designating any RRs
+ KNOT_RRTYPE_TSIG = 250, /*!< TSIG - RFC2845. */
+ KNOT_RRTYPE_IXFR = 251, /*!< IXFR (not an actual RR). */
+ KNOT_RRTYPE_AXFR = 252, /*!< AXFR (not an actual RR). */
+ /*!
+ * \brief A request for mailbox-related records (MB, MG or MR)
+ */
+ KNOT_RRTYPE_MAILB = 253,
+ /*!
+ * \brief A request for mail agent RRs (Obsolete - see MX)
+ */
+ KNOT_RRTYPE_MAILA = 254,
+ KNOT_RRTYPE_ANY = 255, /*!< any type (wildcard) */
+
+ // totally weird numbers (cannot use for indexing)
+ KNOT_RRTYPE_TA = 32768, /*!< DNSSEC Trust Authorities */
+ KNOT_RRTYPE_DLV = 32769, /*!< RFC 4431 */
+
+ /*! \brief Last normal RR type. */
+ KNOT_RRTYPE_LAST = KNOT_RRTYPE_TSIG
+ /*! \todo [TSIG] Is it allright to include all <= RR TSIG?
+ * Because TSIG is normal RR type. */
+};
+
+typedef enum knot_rr_type knot_rr_type_t;
+
+/*! \brief Constants characterising the wire format of RDATA items. */
+enum knot_rdata_wireformat {
+ /*!
+ * \brief Possibly compressed domain name.
+ */
+ KNOT_RDATA_WF_COMPRESSED_DNAME = 50,
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME = 51, /*!< Uncompressed domain name. */
+ KNOT_RDATA_WF_LITERAL_DNAME = 52, /*!< Literal (not downcased) dname. */
+ KNOT_RDATA_WF_BYTE = 1, /*!< 8-bit integer. */
+ KNOT_RDATA_WF_SHORT = 2, /*!< 16-bit integer. */
+ KNOT_RDATA_WF_LONG = 4, /*!< 32-bit integer. */
+ KNOT_RDATA_WF_UINT48 = 8, /*!< 48-bit integer. */
+ KNOT_RDATA_WF_TEXT = 53, /*!< Text string. */
+ KNOT_RDATA_WF_A = 58, /*!< 32-bit IPv4 address. */
+ KNOT_RDATA_WF_AAAA = 16, /*!< 128-bit IPv6 address. */
+ KNOT_RDATA_WF_BINARY = 54, /*!< Binary data (unknown length). */
+ /*!
+ * \brief Binary data preceded by 1 byte length
+ */
+ KNOT_RDATA_WF_BINARYWITHLENGTH = 55,
+ KNOT_RDATA_WF_APL = 56, /*!< APL data. */
+ KNOT_RDATA_WF_IPSECGATEWAY = 57, /*!< IPSECKEY gateway ip4, ip6 or dname. */
+ KNOT_RDATA_WF_BINARYWITHSHORT = 59,
+ KNOT_RDATA_WF_TEXT_SINGLE = 60 /*!< Text string. */
+};
+
+/*! \brief Constants characterising the format of RDATA items in zone file. */
+enum knot_rdata_zoneformat
+{
+ KNOT_RDATA_ZF_DNAME, /* Domain name. */
+ KNOT_RDATA_ZF_LITERAL_DNAME, /* DNS name (not lowercased domain name). */
+ KNOT_RDATA_ZF_TEXT, /* Text string. */
+ KNOT_RDATA_ZF_BYTE, /* 8-bit integer. */
+ KNOT_RDATA_ZF_SHORT, /* 16-bit integer. */
+ KNOT_RDATA_ZF_LONG, /* 32-bit integer. */
+ KNOT_RDATA_ZF_A, /* 32-bit IPv4 address. */
+ KNOT_RDATA_ZF_AAAA, /* 128-bit IPv6 address. */
+ KNOT_RDATA_ZF_RRTYPE, /* RR type. */
+ KNOT_RDATA_ZF_ALGORITHM, /* Cryptographic algorithm. */
+ KNOT_RDATA_ZF_CERTIFICATE_TYPE,
+ KNOT_RDATA_ZF_PERIOD, /* Time period. */
+ KNOT_RDATA_ZF_TIME,
+ KNOT_RDATA_ZF_BASE64, /* Base-64 binary data. */
+ KNOT_RDATA_ZF_BASE32, /* Base-32 binary data. */
+ KNOT_RDATA_ZF_HEX, /* Hexadecimal binary data. */
+ KNOT_RDATA_ZF_HEX_LEN, /* Hexadecimal binary data. Skip initial length byte. */
+ KNOT_RDATA_ZF_NSAP, /* NSAP. */
+ KNOT_RDATA_ZF_APL, /* APL. */
+ KNOT_RDATA_ZF_IPSECGATEWAY, /* IPSECKEY gateway ip4, ip6 or dname. */
+ KNOT_RDATA_ZF_SERVICES, /* Protocol and port number bitmap. */
+ KNOT_RDATA_ZF_NXT, /* NXT type bitmap. */
+ KNOT_RDATA_ZF_NSEC, /* NSEC type bitmap. */
+ KNOT_RDATA_ZF_LOC, /* Location data. */
+ KNOT_RDATA_ZF_UNKNOWN /* Unknown data. */
+};
+
+/*! \brief Constants characterising the wire format of RDATA items. */
+typedef enum knot_rdata_zoneformat knot_rdata_zoneformat_t;
+
+/*! \brief Enum containing wireformat codes. */
+typedef enum knot_rdatawireformat knot_rdata_wireformat_t;
+
+/*! \brief Structure holding RR descriptor. */
+struct knot_rrtype_descriptor {
+ uint16_t type; /*!< RR type */
+ const char *name; /*!< Textual name. */
+ uint8_t length; /*!< Maximum number of RDATA items. */
+
+ /*! \brief Wire format specification for the RDATA. */
+ uint8_t wireformat[KNOT_MAX_RDATA_ITEMS];
+
+ /*! \brief Zone file format specification for the RDATA. */
+ uint8_t zoneformat[KNOT_MAX_RDATA_ITEMS];
+
+ bool fixed_items; /*!< Has fixed number of RDATA items? */
+};
+
+/*! \brief Structure holding RR descriptor. */
+typedef struct knot_rrtype_descriptor knot_rrtype_descriptor_t;
+
+/*!
+ * \brief Gets RR descriptor for given RR type.
+ *
+ * \param type Code of RR type whose descriptor should be returned.
+ *
+ * \return RR descriptor for given type code, NULL descriptor if
+ * unknown type.
+ *
+ * \todo Change return value to const.
+ */
+knot_rrtype_descriptor_t *knot_rrtype_descriptor_by_type(uint16_t type);
+
+/*!
+ * \brief Gets RR descriptor for given RR name.
+ *
+ * \param name Mnemonic of RR type whose descriptor should be returned.
+ *
+ * \return RR descriptor for given name, NULL descriptor if
+ * unknown type.
+ *
+ * \todo Change return value to const.
+ */
+knot_rrtype_descriptor_t *knot_rrtype_descriptor_by_name(const char *name);
+
+/*!
+ * \brief Converts numeric type representation to mnemonic string.
+ *
+ * \param rrtype Type RR type code to be converted.
+ *
+ * \return Mnemonic string if found, str(TYPE[rrtype]) otherwise.
+ */
+const char *knot_rrtype_to_string(uint16_t rrtype);
+
+/*!
+ * \brief Converts mnemonic string representation of a type to numeric one.
+ *
+ * \param name Mnemonic string to be converted.
+ *
+ * \return Correct code if found, 0 otherwise.
+ */
+uint16_t knot_rrtype_from_string(const char *name);
+
+/*!
+ * \brief Converts numeric class representation to string one.
+ *
+ * \param rrclass Class code to be converted.
+ *
+ * \return String represenation of class if found,
+ * str(CLASS[rrclass]) otherwise.
+ */
+const char *knot_rrclass_to_string(uint16_t rrclass);
+
+/*!
+ * \brief Converts string representation of a class to numeric one.
+ *
+ * \param name Class string to be converted.
+ *
+ * \return Correct code if found, 0 otherwise.
+ */
+uint16_t knot_rrclass_from_string(const char *name);
+
+/*!
+ * \brief Returns size of wireformat type in bytes.
+ *
+ * \param wire_type Wireformat type.
+ *
+ * \retval Size of given type on success.
+ * \retval 0 on unknown type or type that has no length.
+ */
+size_t knot_wireformat_size(unsigned int wire_type);
+
+int knot_rrtype_is_metatype(uint16_t type);
+
+#endif /* _KNOT_DESCRIPTOR_H_ */
+
+/*! @} */
+
diff --git a/src/libknot/util/error.h b/src/libknot/util/error.h
new file mode 100644
index 0000000..da45151
--- /dev/null
+++ b/src/libknot/util/error.h
@@ -0,0 +1,87 @@
+/*!
+ * \file error.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Error codes and function for getting error message.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_ERROR_H_
+#define _KNOT_ERROR_H_
+
+#include "common/errors.h"
+
+/*! \brief Error codes used in the library. */
+enum knot_error {
+ KNOT_EOK = 0, /*!< OK */
+
+ /* TSIG errors. */
+ KNOT_TSIG_EBADSIG = -16, /*!< Failed to verify TSIG MAC. */
+ KNOT_TSIG_EBADKEY = -17, /*!< TSIG key not recognized or invalid. */
+ KNOT_TSIG_EBADTIME = -18,/*!< TSIG signing time out of range. */
+
+ /* General errors. */
+ KNOT_ERROR = -10000, /*!< General error. */
+ KNOT_ENOMEM, /*!< Not enough memory. */
+ KNOT_ENOTSUP, /*!< Operation not supported. */
+ KNOT_EAGAIN, /*!< OS lacked necessary resources. */
+ KNOT_ERANGE, /*!< Value is out of range. */
+ KNOT_EBADARG, /*!< Wrong argument supported. */
+ KNOT_EFEWDATA, /*!< Not enough data to parse. */
+ KNOT_ESPACE, /*!< Not enough space provided. */
+ KNOT_EMALF, /*!< Malformed data. */
+ KNOT_ECRYPTO, /*!< Error in crypto library. */
+ KNOT_ENSEC3PAR, /*!< Missing or wrong NSEC3PARAM record. */
+ KNOT_EBADZONE, /*!< Domain name does not belong to the zone. */
+ KNOT_EHASH, /*!< Error in hash table. */
+ KNOT_EZONEIN, /*!< Error inserting zone. */
+ KNOT_ENOZONE, /*!< No such zone found. */
+ KNOT_ENONODE, /*!< No such node in zone found. */
+ KNOT_ENORRSET, /*!< No such RRSet found. */
+ KNOT_EDNAMEPTR, /*!< Domain name pointer larger than allowed. */
+ KNOT_EPAYLOAD, /*!< Payload in OPT RR larger than max wire size. */
+ KNOT_ECRC, /*!< Wrong dump CRC. */
+ KNOT_EPREREQ, /*!< UPDATE prerequisity not met. */
+ KNOT_ENOXFR, /*!< Transfer was not sent. */
+ KNOT_ENOIXFR, /*!< Transfer is not IXFR (is in AXFR format). */
+ KNOT_EXFRREFUSED, /*!< Zone transfer refused by the server. */
+ KNOT_ECONN, /*!< Connection reset. */
+ KNOT_ERROR_COUNT = 30
+};
+
+/*! \brief Table linking error messages to error codes. */
+extern const error_table_t knot_error_msgs[KNOT_ERROR_COUNT];
+
+/*!
+ * \brief Returns error message for the given error code.
+ *
+ * \param code Error code.
+ *
+ * \return String containing the error message.
+ */
+static inline const char *knot_strerror(int code)
+{
+ return error_to_str((const error_table_t*)knot_error_msgs, code);
+}
+
+#endif /* _KNOT_ERROR_H_ */
+
+/*! @} */
diff --git a/src/libknot/util/libknot_error.c b/src/libknot/util/libknot_error.c
new file mode 100644
index 0000000..bc2bed2
--- /dev/null
+++ b/src/libknot/util/libknot_error.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "util/error.h"
+#include "util/utils.h"
+
+#include "common/errors.h"
+
+const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = {
+ {KNOT_EOK, "OK"},
+ {KNOT_ERROR, "General error."},
+ {KNOT_ENOMEM, "Not enough memory."},
+ {KNOT_ENOTSUP, "Operation not supported."},
+ {KNOT_EAGAIN, "OS lacked necessary resources."},
+ {KNOT_ERANGE, "Value is out of range."},
+ {KNOT_EBADARG, "Wrong argument supported."},
+ {KNOT_EFEWDATA, "Not enough data to parse."},
+ {KNOT_ESPACE, "Not enough space provided."},
+ {KNOT_EMALF, "Malformed data."},
+ {KNOT_ECRYPTO, "Error in crypto library."},
+ {KNOT_ENSEC3PAR, "Missing or wrong NSEC3PARAM record."},
+ {KNOT_EBADZONE, "Domain name does not belong to the given zone."},
+ {KNOT_EHASH, "Error in hash table."},
+ {KNOT_EZONEIN, "Error inserting zone."},
+ {KNOT_ENOZONE, "No such zone found."},
+ {KNOT_ENONODE, "No such node in zone found."},
+ {KNOT_ENORRSET, "No such RRSet found."},
+ {KNOT_EDNAMEPTR, "Domain name pointer larger than allowed."},
+ {KNOT_EPAYLOAD, "Payload in OPT RR larger than max wire size."},
+ {KNOT_ECRC, "CRC check failed."},
+ {KNOT_EPREREQ, "UPDATE prerequisity not met."},
+ {KNOT_ENOXFR, "Transfer was not sent."},
+ {KNOT_ENOIXFR, "Transfer is not IXFR (is in AXFR format)."},
+ {KNOT_EXFRREFUSED, "Zone transfer refused by the server."},
+ {KNOT_TSIG_EBADSIG, "Failed to verify TSIG MAC." },
+ {KNOT_TSIG_EBADKEY, "TSIG key not recognized or invalid." },
+ {KNOT_TSIG_EBADTIME, "TSIG signing time out of range." },
+ {KNOT_ECONN, "Connection reset."},
+ {KNOT_ERROR, 0}
+};
diff --git a/src/libknot/util/tolower.c b/src/libknot/util/tolower.c
new file mode 100644
index 0000000..d71c467
--- /dev/null
+++ b/src/libknot/util/tolower.c
@@ -0,0 +1,276 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "util/tolower.h"
+
+const uint8_t char_table[CHAR_TABLE_SIZE] = {
+ '\x00',
+ '\x01',
+ '\x02',
+ '\x03',
+ '\x04',
+ '\x05',
+ '\x06',
+ '\x07',
+ '\x08',
+ '\x09',
+ '\x0A',
+ '\x0B',
+ '\x0C',
+ '\x0D',
+ '\x0E',
+ '\x0F',
+ '\x10',
+ '\x11',
+ '\x12',
+ '\x13',
+ '\x14',
+ '\x15',
+ '\x16',
+ '\x17',
+ '\x18',
+ '\x19',
+ '\x1A',
+ '\x1B',
+ '\x1C',
+ '\x1D',
+ '\x1E',
+ '\x1F',
+ '\x20',
+ '\x21', /* ! */
+ '\x22', /* " */
+ '\x23', /* # */
+ '\x24', /* $ */
+ '\x25', /* % */
+ '\x26', /* & */
+ '\x27', /* ' */
+ '\x28', /* ( */
+ '\x29', /* ) */
+ '\x2A', /* * */
+ '\x2B', /* + */
+ '\x2C', /* , */
+ '\x2D', /* - */
+ '\x2E', /* . */
+ '\x2F', /* / */
+ '\x30', /* 0 */
+ '\x31', /* 1 */
+ '\x32', /* 2 */
+ '\x33', /* 3 */
+ '\x34', /* 4 */
+ '\x35', /* 5 */
+ '\x36', /* 6 */
+ '\x37', /* 7 */
+ '\x38', /* 8 */
+ '\x39', /* 9 */
+ '\x3A', /* : */
+ '\x3B', /* ; */
+ '\x3C', /* < */
+ '\x3D', /* = */
+ '\x3E', /* > */
+ '\x3F', /* ? */
+ '\x40', /* @ */
+ '\x61', /* A */
+ '\x62', /* B */
+ '\x63', /* C */
+ '\x64', /* D */
+ '\x65', /* E */
+ '\x66', /* F */
+ '\x67', /* G */
+ '\x68', /* H */
+ '\x69', /* I */
+ '\x6A', /* J */
+ '\x6B', /* K */
+ '\x6C', /* L */
+ '\x6D', /* M */
+ '\x6E', /* N */
+ '\x6F', /* O */
+ '\x70', /* P */
+ '\x71', /* Q */
+ '\x72', /* R */
+ '\x73', /* S */
+ '\x74', /* T */
+ '\x75', /* U */
+ '\x76', /* V */
+ '\x77', /* W */
+ '\x78', /* X */
+ '\x79', /* Y */
+ '\x7A', /* Z */
+ '\x5B', /* [ */
+ '\x5C', /* \ */
+ '\x5D', /* ] */
+ '\x5E', /* ^ */
+ '\x5F', /* _ */
+ '\x60', /* ` */
+ '\x61', /* a */
+ '\x62', /* b */
+ '\x63', /* c */
+ '\x64', /* d */
+ '\x65', /* e */
+ '\x66', /* f */
+ '\x67', /* g */
+ '\x68', /* h */
+ '\x69', /* i */
+ '\x6A', /* j */
+ '\x6B', /* k */
+ '\x6C', /* l */
+ '\x6D', /* m */
+ '\x6E', /* n */
+ '\x6F', /* o */
+ '\x70', /* p */
+ '\x71', /* q */
+ '\x72', /* r */
+ '\x73', /* s */
+ '\x74', /* t */
+ '\x75', /* u */
+ '\x76', /* v */
+ '\x77', /* w */
+ '\x78', /* x */
+ '\x79', /* y */
+ '\x7A', /* z */
+ '\x7B', /* { */
+ '\x7C', /* | */
+ '\x7D', /* } */
+ '\x7E', /* ~ */
+ '\x7F',
+ '\x80',
+ '\x81',
+ '\x82',
+ '\x83',
+ '\x84',
+ '\x85',
+ '\x86',
+ '\x87',
+ '\x88',
+ '\x89',
+ '\x8A',
+ '\x8B',
+ '\x8C',
+ '\x8D',
+ '\x8E',
+ '\x8F',
+ '\x90',
+ '\x91',
+ '\x92',
+ '\x93',
+ '\x94',
+ '\x95',
+ '\x96',
+ '\x97',
+ '\x98',
+ '\x99',
+ '\x9A',
+ '\x9B',
+ '\x9C',
+ '\x9D',
+ '\x9E',
+ '\x9F',
+ '\xA0',
+ '\xA1',
+ '\xA2',
+ '\xA3',
+ '\xA4',
+ '\xA5',
+ '\xA6',
+ '\xA7',
+ '\xA8',
+ '\xA9',
+ '\xAA',
+ '\xAB',
+ '\xAC',
+ '\xAD',
+ '\xAE',
+ '\xAF',
+ '\xB0',
+ '\xB1',
+ '\xB2',
+ '\xB3',
+ '\xB4',
+ '\xB5',
+ '\xB6',
+ '\xB7',
+ '\xB8',
+ '\xB9',
+ '\xBA',
+ '\xBB',
+ '\xBC',
+ '\xBD',
+ '\xBE',
+ '\xBF',
+ '\xC0',
+ '\xC1',
+ '\xC2',
+ '\xC3',
+ '\xC4',
+ '\xC5',
+ '\xC6',
+ '\xC7',
+ '\xC8',
+ '\xC9',
+ '\xCA',
+ '\xCB',
+ '\xCC',
+ '\xCD',
+ '\xCE',
+ '\xCF',
+ '\xD0',
+ '\xD1',
+ '\xD2',
+ '\xD3',
+ '\xD4',
+ '\xD5',
+ '\xD6',
+ '\xD7',
+ '\xD8',
+ '\xD9',
+ '\xDA',
+ '\xDB',
+ '\xDC',
+ '\xDD',
+ '\xDE',
+ '\xDF',
+ '\xE0',
+ '\xE1',
+ '\xE2',
+ '\xE3',
+ '\xE4',
+ '\xE5',
+ '\xE6',
+ '\xE7',
+ '\xE8',
+ '\xE9',
+ '\xEA',
+ '\xEB',
+ '\xEC',
+ '\xED',
+ '\xEE',
+ '\xEF',
+ '\xF0',
+ '\xF1',
+ '\xF2',
+ '\xF3',
+ '\xF4',
+ '\xF5',
+ '\xF6',
+ '\xF7',
+ '\xF8',
+ '\xF9',
+ '\xFA',
+ '\xFB',
+ '\xFC',
+ '\xFD',
+ '\xFE',
+ '\xFF',
+};
diff --git a/src/libknot/util/tolower.h b/src/libknot/util/tolower.h
new file mode 100644
index 0000000..6b9e98c
--- /dev/null
+++ b/src/libknot/util/tolower.h
@@ -0,0 +1,57 @@
+/*!
+ * \file tolower.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Table for converting ASCII characters to lowercase.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_TOLOWER_H_
+#define _KNOT_TOLOWER_H_
+
+#include <stdint.h>
+
+/*! \brief Size of the character conversion table. */
+#define KNOT_CHAR_TABLE_SIZE 256
+
+enum {
+ /*! \brief Size of the character conversion table. */
+ CHAR_TABLE_SIZE = KNOT_CHAR_TABLE_SIZE
+};
+
+/*! \brief Character table mapping uppercase letters to lowercase. */
+extern const uint8_t char_table[CHAR_TABLE_SIZE];
+
+/*!
+ * \brief Converts ASCII character to lowercase.
+ *
+ * \param c ASCII character code.
+ *
+ * \return \a c converted to lowercase (or \a c if not applicable).
+ */
+static inline uint8_t knot_tolower(uint8_t c) {
+#if KNOT_CHAR_TABLE_SIZE < 256
+ assert(c < CHAR_TABLE_SIZE);
+#endif
+ return char_table[c];
+}
+
+#endif /* _KNOT_TOLOWER_H_ */
diff --git a/src/libknot/util/utils.c b/src/libknot/util/utils.c
new file mode 100644
index 0000000..17b33a7
--- /dev/null
+++ b/src/libknot/util/utils.c
@@ -0,0 +1,127 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "util/utils.h"
+#include "common/WELL1024a.h"
+
+/*----------------------------------------------------------------------------*/
+
+knot_lookup_table_t *knot_lookup_by_name(knot_lookup_table_t *table,
+ const char *name)
+{
+ while (table->name != NULL) {
+ if (strcasecmp(name, table->name) == 0) {
+ return table;
+ }
+ table++;
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_lookup_table_t *knot_lookup_by_id(knot_lookup_table_t *table,
+ int id)
+{
+ while (table->name != NULL) {
+ if (table->id == id) {
+ return table;
+ }
+ table++;
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+size_t knot_strlcpy(char *dst, const char *src, size_t size)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = size;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0) {
+ break;
+ }
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (size != 0) {
+ *d = '\0'; /* NUL-terminate dst */
+ }
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
+/*! \brief TLS key for rand seed. */
+static pthread_key_t _qr_key;
+static pthread_once_t _qr_once = PTHREAD_ONCE_INIT;
+
+/*! \brief TLS key initializer. */
+static void _qr_init()
+{
+ (void) pthread_key_create(&_qr_key, NULL);
+ (void) pthread_setspecific(_qr_key, (void*)time(0));
+}
+
+size_t knot_quick_rand()
+{
+ (void) pthread_once(&_qr_once, _qr_init);
+ size_t x = (size_t)pthread_getspecific(_qr_key);
+
+ /* Numerical Recipes in C.
+ * The Art of Scientific Computing, 2nd Edition,
+ * 1992, ISBN 0-521-43108-5.
+ * Page 284.
+ */
+ x = 1664525L * x + 1013904223L;
+ (void) pthread_setspecific(_qr_key, (void*)x);
+ return x;
+}
+
+uint16_t knot_random_id()
+{
+ return (uint16_t)(tls_rand() * ((uint16_t)~0));
+}
+
+struct flock* knot_file_lock(short type, short whence)
+{
+ static struct flock ret;
+ ret.l_type = type;
+ ret.l_start = 0;
+ ret.l_whence = whence;
+ ret.l_len = 0;
+ ret.l_pid = getpid();
+ return &ret;
+}
+
diff --git a/src/libknot/util/utils.h b/src/libknot/util/utils.h
new file mode 100644
index 0000000..f43b8f0
--- /dev/null
+++ b/src/libknot/util/utils.h
@@ -0,0 +1,196 @@
+/*!
+ * \file utils.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Various utilities.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_UTILS_H_
+#define _KNOT_UTILS_H_
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/*!
+ * \brief A general purpose lookup table.
+ *
+ * \note Taken from NSD.
+ */
+struct knot_lookup_table {
+ int id;
+ const char *name;
+};
+
+typedef struct knot_lookup_table knot_lookup_table_t;
+
+/*!
+ * \brief Looks up the given name in the lookup table.
+ *
+ * \param table Lookup table.
+ * \param name Name to look up.
+ *
+ * \return Item in the lookup table with the given name or NULL if no such is
+ * present.
+ */
+knot_lookup_table_t *knot_lookup_by_name(knot_lookup_table_t *table,
+ const char *name);
+
+/*!
+ * \brief Looks up the given id in the lookup table.
+ *
+ * \param table Lookup table.
+ * \param id ID to look up.
+ *
+ * \return Item in the lookup table with the given id or NULL if no such is
+ * present.
+ */
+knot_lookup_table_t *knot_lookup_by_id(knot_lookup_table_t *table,
+ int id);
+
+/*!
+ * \brief Strlcpy - safe string copy function, based on FreeBSD implementation.
+ *
+ * http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/
+ *
+ * \param dst Destination string.
+ * \param src Source string.
+ * \param size How many characters to copy - 1.
+ *
+ * \return strlen(src), if retval >= siz, truncation occurred.
+ */
+size_t knot_strlcpy(char *dst, const char *src, size_t size);
+
+/*
+ * Writing / reading arbitrary data to / from wireformat.
+ */
+
+/*!
+ * \brief Reads 2 bytes from the wireformat data.
+ *
+ * \param pos Data to read the 2 bytes from.
+ *
+ * \return The 2 bytes read, in inverse endian.
+ */
+static inline uint16_t knot_wire_read_u16(const uint8_t *pos)
+{
+ return (pos[0] << 8) | pos[1];
+}
+
+/*!
+ * \brief Reads 4 bytes from the wireformat data.
+ *
+ * \param pos Data to read the 4 bytes from.
+ *
+ * \return The 4 bytes read, in inverse endian.
+ */
+static inline uint32_t knot_wire_read_u32(const uint8_t *pos)
+{
+ return (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) | pos[3];
+}
+
+/*!
+ * \brief Reads 6 bytes from the wireformat data.
+ *
+ * \param pos Data to read the 6 bytes from.
+ *
+ * \return The 6 bytes read, in inverse endian.
+ */
+static inline uint64_t knot_wire_read_u48(const uint8_t *pos)
+{
+ return ((uint64_t)(pos[0]) << 40) | ((uint64_t)(pos[1]) << 32) | (pos[2] << 24) |
+ (pos[3] << 16) | (pos[4] << 8) | pos[5];
+}
+
+/*!
+ * \brief Writes 2 bytes in wireformat.
+ *
+ * The endian of the data is inverted.
+ *
+ * \param pos Position where to put the 2 bytes.
+ * \param data Data to put.
+ */
+static inline void knot_wire_write_u16(uint8_t *pos, uint16_t data)
+{
+ pos[0] = (uint8_t)((data >> 8) & 0xff);
+ pos[1] = (uint8_t)(data & 0xff);
+}
+
+/*!
+ * \brief Writes 4 bytes in wireformat.
+ *
+ * The endian of the data is inverted.
+ *
+ * \param pos Position where to put the 4 bytes.
+ * \param data Data to put.
+ */
+static inline void knot_wire_write_u32(uint8_t *pos, uint32_t data)
+{
+ pos[0] = (uint8_t)((data >> 24) & 0xff);
+ pos[1] = (uint8_t)((data >> 16) & 0xff);
+ pos[2] = (uint8_t)((data >> 8) & 0xff);
+ pos[3] = (uint8_t)(data & 0xff);
+}
+
+/*!
+ * \brief Writes 6 bytes in wireformat.
+ *
+ * The endian of the data is inverted.
+ *
+ * \param pos Position where to put the 4 bytes.
+ * \param data Data to put.
+ */
+static inline void knot_wire_write_u48(uint8_t *pos, uint64_t data)
+{
+ pos[0] = (uint8_t)((data >> 40) & 0xff);
+ pos[1] = (uint8_t)((data >> 32) & 0xff);
+ pos[2] = (uint8_t)((data >> 24) & 0xff);
+ pos[3] = (uint8_t)((data >> 16) & 0xff);
+ pos[4] = (uint8_t)((data >> 8) & 0xff);
+ pos[5] = (uint8_t)(data & 0xff);
+}
+
+/*!
+ * \brief Linear congruential generator.
+ *
+ * Simple pseudorandom generator for general purpose.
+ * \warning Do not use for cryptography.
+ * \return Random number <0, (size_t)~0>
+ */
+size_t knot_quick_rand();
+
+uint16_t knot_random_id();
+
+/*!
+ * \brief Helper function for simple locking.
+ *
+ * \param type Type of lock.
+ * \param type Starting position of lock.
+ *
+ * \return Locking structure.
+ */
+struct flock* knot_file_lock(short type, short whence);
+
+#endif /* _KNOT_UTILS_H_ */
+
+/*! @} */
+
diff --git a/src/libknot/util/wire.h b/src/libknot/util/wire.h
new file mode 100644
index 0000000..0a24ff1
--- /dev/null
+++ b/src/libknot/util/wire.h
@@ -0,0 +1,926 @@
+/*!
+ * \file wire.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Functions for manipulating and parsing raw data in DNS packets.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_WIRE_H_
+#define _KNOT_WIRE_H_
+
+#include <stdint.h>
+#include <assert.h>
+
+#include "util/utils.h"
+
+/*! \brief Offset of DNS header fields in wireformat. */
+enum knot_wire_offsets {
+ KNOT_WIRE_OFFSET_ID = 0,
+ KNOT_WIRE_OFFSET_FLAGS1 = 2,
+ KNOT_WIRE_OFFSET_FLAGS2 = 3,
+ KNOT_WIRE_OFFSET_QDCOUNT = 4,
+ KNOT_WIRE_OFFSET_ANCOUNT = 6,
+ KNOT_WIRE_OFFSET_NSCOUNT = 8,
+ KNOT_WIRE_OFFSET_ARCOUNT = 10
+};
+
+/*! \brief Minimum size for some parts of the DNS packet. */
+enum knot_wire_sizes {
+ KNOT_WIRE_HEADER_SIZE = 12,
+ KNOT_WIRE_QUESTION_MIN_SIZE = 5,
+ KNOT_WIRE_RR_MIN_SIZE = 11
+};
+
+/*
+ * Packet header manipulation functions.
+ */
+
+/*!
+ * \brief Returns the ID from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return DNS packet ID.
+ */
+static inline uint16_t knot_wire_get_id(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ID);
+}
+
+/*!
+ * \brief Sets the ID to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param id DNS packet ID.
+ */
+static inline void knot_wire_set_id(uint8_t *packet, uint16_t id)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ID, id);
+}
+
+/*!
+ * \brief Returns the first byte of flags from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return First byte of DNS flags.
+ */
+static inline uint8_t knot_wire_get_flags1(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1);
+}
+
+/*!
+ * \brief Sets the first byte of flags to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param flags1 First byte of the DNS flags.
+ */
+static inline uint8_t knot_wire_set_flags1(uint8_t *packet, uint8_t flags1)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) = flags1;
+}
+
+/*!
+ * \brief Returns the second byte of flags from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Second byte of DNS flags.
+ */
+static inline uint8_t knot_wire_get_flags2(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2);
+}
+
+/*!
+ * \brief Sets the second byte of flags to the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param flags2 Second byte of the DNS flags.
+ */
+static inline uint8_t knot_wire_set_flags2(uint8_t *packet, uint8_t flags2)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) = flags2;
+}
+
+/*!
+ * \brief Returns the QDCOUNT (count of Question entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return QDCOUNT (count of Question entries in the packet).
+ */
+static inline uint16_t knot_wire_get_qdcount(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT);
+}
+
+/*!
+ * \brief Sets the QDCOUNT (count of Question entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param qdcount QDCOUNT (count of Question entries in the packet).
+ */
+static inline void knot_wire_set_qdcount(uint8_t *packet, uint16_t qdcount)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_QDCOUNT, qdcount);
+}
+
+/*!
+ * \brief Returns the ANCOUNT (count of Answer entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return ANCOUNT (count of Answer entries in the packet).
+ */
+static inline uint16_t knot_wire_get_ancount(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT);
+}
+
+/*!
+ * \brief Sets the ANCOUNT (count of Answer entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param ancount ANCOUNT (count of Answer entries in the packet).
+ */
+static inline void knot_wire_set_ancount(uint8_t *packet, uint16_t ancount)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ANCOUNT, ancount);
+}
+
+/*!
+ * \brief Returns the NSCOUNT (count of Authority entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return NSCOUNT (count of Authority entries in the packet).
+ */
+static inline uint16_t knot_wire_get_nscount(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT);
+}
+
+/*!
+ * \brief Sets the NSCOUNT (count of Authority entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param nscount NSCOUNT (count of Authority entries in the packet).
+ */
+static inline void knot_wire_set_nscount(uint8_t *packet, uint16_t nscount)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_NSCOUNT, nscount);
+}
+
+/*!
+ * \brief Returns the ARCOUNT (count of Additional entries) from wire format of
+ * the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return ARCOUNT (count of Additional entries in the packet).
+ */
+static inline uint16_t knot_wire_get_arcount(const uint8_t *packet)
+{
+ return knot_wire_read_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT);
+}
+
+/*!
+ * \brief Sets the ARCOUNT (count of Additional entries) to wire format of the
+ * packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param arcount ARCOUNT (count of Additional entries in the packet).
+ */
+static inline void knot_wire_set_arcount(uint8_t *packet, uint16_t arcount)
+{
+ knot_wire_write_u16(packet + KNOT_WIRE_OFFSET_ARCOUNT, arcount);
+}
+
+/*
+ * Packet header flags manipulation functions.
+ */
+/*! \brief Constants for DNS header flags in the first flags byte. */
+enum knot_wire_flags1_consts {
+ KNOT_WIRE_RD_MASK = (uint8_t)0x01U, /*!< RD bit mask. */
+ KNOT_WIRE_RD_SHIFT = 0, /*!< RD bit shift. */
+ KNOT_WIRE_TC_MASK = (uint8_t)0x02U, /*!< TC bit mask. */
+ KNOT_WIRE_TC_SHIFT = 1, /*!< TC bit shift. */
+ KNOT_WIRE_AA_MASK = (uint8_t)0x04U, /*!< AA bit mask. */
+ KNOT_WIRE_AA_SHIFT = 2, /*!< AA bit shift. */
+ KNOT_WIRE_OPCODE_MASK = (uint8_t)0x78U, /*!< OPCODE mask. */
+ KNOT_WIRE_OPCODE_SHIFT = 3, /*!< OPCODE shift. */
+ KNOT_WIRE_QR_MASK = (uint8_t)0x80U, /*!< QR bit mask. */
+ KNOT_WIRE_QR_SHIFT = 7 /*!< QR bit shift. */
+};
+
+/*! \brief Constants for DNS header flags in the second flags byte. */
+enum knot_wire_flags2_consts {
+ KNOT_WIRE_RCODE_MASK = (uint8_t)0x0fU, /*!< RCODE mask. */
+ KNOT_WIRE_RCODE_SHIFT = 0, /*!< RCODE shift. */
+ KNOT_WIRE_CD_MASK = (uint8_t)0x10U, /*!< CD bit mask. */
+ KNOT_WIRE_CD_SHIFT = 4, /*!< CD bit shift. */
+ KNOT_WIRE_AD_MASK = (uint8_t)0x20U, /*!< AD bit mask. */
+ KNOT_WIRE_AD_SHIFT = 5, /*!< AD bit shift. */
+ KNOT_WIRE_Z_MASK = (uint8_t)0x40U, /*!< Zero bit mask. */
+ KNOT_WIRE_Z_SHIFT = 6, /*!< Zero bit shift. */
+ KNOT_WIRE_RA_MASK = (uint8_t)0x80U, /*!< RA bit mask. */
+ KNOT_WIRE_RA_SHIFT = 7 /*!< RA bit shift. */
+};
+
+/*
+ * Functions for getting / setting / clearing flags and codes directly in packet
+ */
+
+/*!
+ * \brief Returns the RD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the RD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_rd(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Sets the RD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_rd(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Clears the RD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_flags_clear_rd(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Returns the TC bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the TC bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_tc(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Sets the TC bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_tc(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Clears the TC bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_tc(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Returns the AA bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the AA bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_aa(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Sets the AA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_aa(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Clears the AA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_aa(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Returns the OPCODE from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return OPCODE of the packet.
+ */
+static inline uint8_t knot_wire_get_opcode(const uint8_t *packet)
+{
+ return (*(packet + KNOT_WIRE_OFFSET_FLAGS1)
+ & KNOT_WIRE_OPCODE_MASK) >> KNOT_WIRE_OPCODE_SHIFT;
+}
+
+/*!
+ * \brief Sets the OPCODE in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param opcode OPCODE to set.
+ */
+static inline void knot_wire_set_opcode(uint8_t *packet, short opcode)
+{
+ uint8_t *flags1 = packet + KNOT_WIRE_OFFSET_FLAGS1;
+ *flags1 = (*flags1 & ~KNOT_WIRE_OPCODE_MASK)
+ | ((opcode) << KNOT_WIRE_OPCODE_SHIFT);
+}
+
+/*!
+ * \brief Returns the QR bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the QR bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_qr(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS1) & KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Sets the QR bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_qr(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) |= KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Clears the QR bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_qr(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS1) &= ~KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Returns the RCODE from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return RCODE of the packet.
+ */
+static inline uint8_t knot_wire_get_rcode(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2)
+ & KNOT_WIRE_RCODE_MASK;
+}
+
+/*!
+ * \brief Sets the RCODE in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ * \param rcode RCODE to set.
+ */
+static inline void knot_wire_set_rcode(uint8_t *packet, short rcode)
+{
+ uint8_t *flags2 = packet + KNOT_WIRE_OFFSET_FLAGS2;
+ *flags2 = (*flags2 & ~KNOT_WIRE_RCODE_MASK) | (rcode);
+}
+
+/*!
+ * \brief Returns the CD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the CD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_cd(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Sets the CD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_cd(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Clears the CD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_cd(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Returns the AD bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the AD bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_ad(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Sets the AD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_ad(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Clears the AD bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_ad(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Returns the Zero bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the Zero bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_z(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Sets the Zero bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_z(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Clears the Zero bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_z(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Returns the RA bit from wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ *
+ * \return Flags with only the RA bit according to its setting in the packet.
+ */
+static inline uint8_t knot_wire_get_ra(const uint8_t *packet)
+{
+ return *(packet + KNOT_WIRE_OFFSET_FLAGS2) & KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Sets the RA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_set_ra(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) |= KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Clears the RA bit in the wire format of the packet.
+ *
+ * \param packet Wire format of the packet.
+ */
+static inline void knot_wire_clear_ra(uint8_t *packet)
+{
+ *(packet + KNOT_WIRE_OFFSET_FLAGS2) &= ~KNOT_WIRE_RA_MASK;
+}
+
+/*
+ * Functions for getting / setting / clearing flags in flags variable
+ */
+
+/*!
+ * \brief Returns the RD bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the RD bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_rd(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Sets the RD bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_rd(uint8_t *flags1)
+{
+ *flags1 |= KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Clears the RD bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_flags_clear_rd(uint8_t *flags1)
+{
+ *flags1 &= ~KNOT_WIRE_RD_MASK;
+}
+
+/*!
+ * \brief Returns the TC bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the TC bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_tc(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Sets the TC bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_tc(uint8_t *flags1)
+{
+ *flags1 |= KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Clears the TC bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_tc(uint8_t *flags1)
+{
+ *flags1 &= ~KNOT_WIRE_TC_MASK;
+}
+
+/*!
+ * \brief Returns the AA bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the AA bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_aa(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Sets the AA bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_aa(uint8_t *flags1)
+{
+ *flags1 |= KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Clears the AA bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_aa(uint8_t *flags1)
+{
+ *flags1 &= ~KNOT_WIRE_AA_MASK;
+}
+
+/*!
+ * \brief Returns the OPCODE from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return OPCODE
+ */
+static inline uint8_t knot_wire_flags_get_opcode(uint8_t flags1)
+{
+ return (flags1 & KNOT_WIRE_OPCODE_MASK)
+ >> KNOT_WIRE_OPCODE_SHIFT;
+}
+
+/*!
+ * \brief Sets the OPCODE in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ * \param opcode OPCODE to set.
+ */
+static inline void knot_wire_flags_set_opcode(uint8_t *flags1, short opcode)
+{
+ *flags1 = (*flags1 & ~KNOT_WIRE_OPCODE_MASK)
+ | ((opcode) << KNOT_WIRE_OPCODE_SHIFT);
+}
+
+/*!
+ * \brief Returns the QR bit from the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ *
+ * \return Flags byte with only the QR bit according to its setting in
+ * \a flags1.
+ */
+static inline uint8_t knot_wire_flags_get_qr(uint8_t flags1)
+{
+ return flags1 & KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Sets the QR bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_qr(uint8_t *flags1)
+{
+ *flags1 |= KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Clears the QR bit in the first byte of flags.
+ *
+ * \param flags1 First byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_qr(uint8_t *flags1)
+{
+ *flags1 &= ~KNOT_WIRE_QR_MASK;
+}
+
+/*!
+ * \brief Returns the RCODE from the second byte of flags.
+ *
+ * \param flags2 First byte of DNS header flags.
+ *
+ * \return RCODE
+ */
+static inline uint8_t knot_wire_flags_get_rcode(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_RCODE_MASK;
+}
+
+/*!
+ * \brief Sets the RCODE in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ * \param rcode RCODE to set.
+ */
+static inline void knot_wire_flags_set_rcode(uint8_t *flags2, short rcode)
+{
+ *flags2 = (*flags2 & ~KNOT_WIRE_RCODE_MASK) | (rcode);
+}
+
+/*!
+ * \brief Returns the CD bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the CD bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_cd(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Sets the CD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_cd(uint8_t *flags2)
+{
+ *flags2 |= KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Clears the CD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_cd(uint8_t *flags2)
+{
+ *flags2 &= ~KNOT_WIRE_CD_MASK;
+}
+
+/*!
+ * \brief Returns the AD bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the AD bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_ad(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Sets the AD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_ad(uint8_t *flags2)
+{
+ *flags2 |= KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Clears the AD bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_ad(uint8_t *flags2)
+{
+ *flags2 &= ~KNOT_WIRE_AD_MASK;
+}
+
+/*!
+ * \brief Returns the Zero bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the Zero bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_z(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Sets the Zero bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_z(uint8_t *flags2)
+{
+ *flags2 |= KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Clears the Zero bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_z(uint8_t *flags2)
+{
+ *flags2 &= ~KNOT_WIRE_Z_MASK;
+}
+
+/*!
+ * \brief Returns the RA bit from the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ *
+ * \return Flags byte with only the RA bit according to its setting in
+ * \a flags2.
+ */
+static inline uint8_t knot_wire_flags_get_ra(uint8_t flags2)
+{
+ return flags2 & KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Sets the RA bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_set_ra(uint8_t *flags2)
+{
+ *flags2 |= KNOT_WIRE_RA_MASK;
+}
+
+/*!
+ * \brief Clears the RA bit in the second byte of flags.
+ *
+ * \param flags2 Second byte of DNS header flags.
+ */
+static inline void knot_wire_flags_clear_ra(uint8_t *flags2)
+{
+ *flags2 &= ~KNOT_WIRE_RA_MASK;
+}
+
+/*
+ * Pointer manipulation
+ */
+
+enum knot_wire_pointer_consts {
+ /*! \brief DNS packet pointer designation (first two bits set to 1). */
+ KNOT_WIRE_PTR = (uint8_t)0xc0U
+};
+
+/*!
+ * \brief Creates a DNS packet pointer and stores it in wire format.
+ *
+ * \param pos Position where tu put the pointer.
+ * \param ptr Relative position of the item to which the pointer should point in
+ * the wire format of the packet.
+ */
+static inline void knot_wire_put_pointer(uint8_t *pos, size_t ptr)
+{
+ uint16_t p = ptr;
+ knot_wire_write_u16(pos, p);
+ assert((pos[0] & KNOT_WIRE_PTR) == 0);
+ pos[0] |= KNOT_WIRE_PTR;
+}
+
+static inline int knot_wire_is_pointer(const uint8_t *pos)
+{
+ return ((pos[0] & KNOT_WIRE_PTR) != 0);
+}
+
+static inline size_t knot_wire_get_pointer(const uint8_t *pos)
+{
+ /*! \todo memcpy() is not needed, may be directly assigned. */
+ uint16_t p = 0;
+ memcpy(&p, pos, 2);
+ p &= ~KNOT_WIRE_PTR;
+
+ uint16_t p2 = knot_wire_read_u16((uint8_t *)&p);
+ return p2;
+}
+
+#endif /* _KNOT_WIRE_H_ */
+
+/*! @} */
diff --git a/src/libknot/zone/dname-table.c b/src/libknot/zone/dname-table.c
new file mode 100644
index 0000000..c41b4bd
--- /dev/null
+++ b/src/libknot/zone/dname-table.c
@@ -0,0 +1,310 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "zone/dname-table.h"
+#include "util/error.h"
+
+/*!< Tree functions. */
+TREE_DEFINE(dname_table_node, avl);
+
+struct knot_dname_table_fnc_data {
+ void (*func)(knot_dname_t *dname, void *data);
+ void *data;
+};
+
+static void knot_dname_table_apply(struct dname_table_node *node, void *data)
+{
+ assert(data != NULL);
+ assert(node != NULL);
+ struct knot_dname_table_fnc_data *d =
+ (struct knot_dname_table_fnc_data *)data;
+ d->func(node->dname, d->data);
+}
+
+/*!
+ * \brief Comparison function to be used with tree.
+ *
+ * \param n1 First dname to be compared.
+ * \param n2 Second dname to be compared.
+ *
+ * \return strncmp of dname's wireformats.
+ */
+static int compare_dname_table_nodes(struct dname_table_node *n1,
+ struct dname_table_node *n2)
+{
+ assert(n1 && n2);
+ return (strncmp((char *)n1->dname->name, (char *)n2->dname->name,
+ (n1->dname->size < n2->dname->size) ?
+ (n1->dname->size):(n2->dname->size)));
+}
+
+/*!
+ * \brief Deletes tree node along with its domain name.
+ *
+ * \param node Node to be deleted.
+ * \param data If <> 0, dname in the node will be freed as well.
+ */
+static void delete_dname_table_node(struct dname_table_node *node, void *data)
+{
+ if ((ssize_t)data == 1) {
+ knot_dname_release(node->dname);
+ } else if ((ssize_t)data == 2) {
+ knot_dname_free(&node->dname);
+ }
+
+ /*!< \todo it would be nice to set pointers to NULL. */
+ free(node);
+}
+
+static void knot_dname_table_delete_subtree(struct dname_table_node *root)
+{
+ if (root == NULL) {
+ return;
+ }
+
+ knot_dname_table_delete_subtree(root->avl.avl_left);
+ knot_dname_table_delete_subtree(root->avl.avl_right);
+ free(root);
+}
+
+static int knot_dname_table_copy_node(const struct dname_table_node *from,
+ struct dname_table_node **to)
+{
+ if (from == NULL) {
+ return KNOT_EOK;
+ }
+
+ *to = (struct dname_table_node *)
+ malloc(sizeof(struct dname_table_node));
+ if (*to == NULL) {
+ return KNOT_ENOMEM;
+ }
+ memset(*to, 0, sizeof(struct dname_table_node));
+
+ (*to)->dname = from->dname;
+ knot_dname_retain((*to)->dname);
+ (*to)->avl.avl_height = from->avl.avl_height;
+
+ int ret = knot_dname_table_copy_node(from->avl.avl_left,
+ &(*to)->avl.avl_left);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = knot_dname_table_copy_node(from->avl.avl_right,
+ &(*to)->avl.avl_right);
+ if (ret != KNOT_EOK) {
+ knot_dname_table_delete_subtree((*to)->avl.avl_left);
+ (*to)->avl.avl_left = NULL;
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+knot_dname_table_t *knot_dname_table_new()
+{
+ knot_dname_table_t *ret = malloc(sizeof(knot_dname_table_t));
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ ret->tree = malloc(sizeof(table_tree_t));
+ if (ret->tree == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret);
+ return NULL;
+ }
+
+ TREE_INIT(ret->tree, compare_dname_table_nodes);
+
+ ret->id_counter = 1;
+
+ return ret;
+}
+
+knot_dname_t *knot_dname_table_find_dname(const knot_dname_table_t *table,
+ knot_dname_t *dname)
+{
+ if (table == NULL || dname == NULL) {
+ return NULL;
+ }
+
+ struct dname_table_node *node = NULL;
+ struct dname_table_node sought;
+ sought.dname = dname;
+
+ node = TREE_FIND(table->tree, dname_table_node, avl, &sought);
+
+ if (node == NULL) {
+ return NULL;
+ } else {
+ /* Increase reference counter. */
+ knot_dname_retain(node->dname);
+
+ return node->dname;
+ }
+}
+
+int knot_dname_table_add_dname(knot_dname_table_t *table,
+ knot_dname_t *dname)
+{
+ if (dname == NULL || table == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ /* Node for insertion has to be created */
+ struct dname_table_node *node =
+ malloc(sizeof(struct dname_table_node));
+ CHECK_ALLOC_LOG(node, KNOT_ENOMEM);
+
+ // convert the dname to lowercase
+ knot_dname_to_lower(dname);
+
+ node->dname = dname;
+ node->avl.avl_height = 0;
+ node->avl.avl_left = NULL;
+ node->avl.avl_right = NULL;
+
+ node->dname->id = table->id_counter++;
+ assert(node->dname->id != 0);
+
+ /* Increase reference counter. */
+ knot_dname_retain(dname);
+
+ TREE_INSERT(table->tree, dname_table_node, avl, node);
+ return KNOT_EOK;
+}
+
+int knot_dname_table_add_dname_check(knot_dname_table_t *table,
+ knot_dname_t **dname)
+{
+ knot_dname_t *found_dname = NULL;
+
+ if (table == NULL || dname == NULL || *dname == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ /* Fetch dname, need to release it later. */
+ found_dname = knot_dname_table_find_dname(table ,*dname);
+
+ if (!found_dname) {
+ /* Store reference in table. */
+ return knot_dname_table_add_dname(table, *dname);
+ } else {
+ /*! \todo Remove the check for equality. */
+ if (found_dname != *dname) {
+ /* Replace dname with found. */
+ knot_dname_release(*dname);
+ *dname = found_dname;
+ return 1; /*! \todo Error code? */
+
+ } else {
+
+ /* If the dname is already in the table, there is already
+ * a reference to it.
+ */
+ knot_dname_release(found_dname);
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int knot_dname_table_shallow_copy(knot_dname_table_t *from,
+ knot_dname_table_t *to)
+{
+ to->id_counter = from->id_counter;
+
+ if (to->tree == NULL) {
+ to->tree = malloc(sizeof(table_tree_t));
+ if (to->tree == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ TREE_INIT(to->tree, compare_dname_table_nodes);
+ }
+
+ return knot_dname_table_copy_node(from->tree->th_root,
+ &to->tree->th_root);
+}
+
+void knot_dname_table_free(knot_dname_table_t **table)
+{
+ if (table == NULL || *table == NULL) {
+ return;
+ }
+
+ /* Walk the tree and free each node, but not the dnames. */
+ TREE_POST_ORDER_APPLY((*table)->tree, dname_table_node, avl,
+ delete_dname_table_node, 0);
+
+ free((*table)->tree);
+
+ free(*table);
+ *table = NULL;
+}
+
+void knot_dname_table_deep_free(knot_dname_table_t **table)
+{
+ if (table == NULL || *table == NULL) {
+ return;
+ }
+
+ /* Walk the tree and free each node, but free the dnames. */
+ TREE_POST_ORDER_APPLY((*table)->tree, dname_table_node, avl,
+ delete_dname_table_node, (void *) 1);
+
+ free((*table)->tree);
+
+ free(*table);
+ *table = NULL;
+}
+
+void knot_dname_table_destroy(knot_dname_table_t **table)
+{
+ if (table == NULL || *table == NULL) {
+ return;
+ }
+
+ /* Walk the tree and free each node, but free the dnames. */
+ TREE_POST_ORDER_APPLY((*table)->tree, dname_table_node, avl,
+ delete_dname_table_node, (void *) 2);
+
+ free((*table)->tree);
+
+ free(*table);
+ *table = NULL;
+}
+
+void knot_dname_table_tree_inorder_apply(const knot_dname_table_t *table,
+ void (*applied_function)(knot_dname_t *node,
+ void *data),
+ void *data)
+{
+ struct knot_dname_table_fnc_data d;
+ d.data = data;
+ d.func = applied_function;
+
+ TREE_FORWARD_APPLY(table->tree, dname_table_node, avl,
+ knot_dname_table_apply, &d);
+}
+
diff --git a/src/libknot/zone/dname-table.h b/src/libknot/zone/dname-table.h
new file mode 100644
index 0000000..dd86eaf
--- /dev/null
+++ b/src/libknot/zone/dname-table.h
@@ -0,0 +1,168 @@
+/*!
+ * \file dname-table.h
+ *
+ * \author Jan Kadlec <jan.kadlec.@nic.cz>
+ *
+ * \brief Structures representing dname table and functions for
+ * manipulating these structures.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_DNAME_TABLE_H_
+#define _KNOT_DNAME_TABLE_H_
+
+#include <config.h>
+
+#include "common/tree.h"
+
+#include "dname.h"
+#include "common.h"
+
+
+/*!
+ * \brief Structure encapsulating
+ */
+struct dname_table_node {
+ knot_dname_t *dname; /*!< Dname stored in node. */
+ TREE_ENTRY(dname_table_node) avl; /*!< Tree variables. */
+};
+
+/*!
+ * \brief Tree structure.
+ */
+typedef TREE_HEAD(avl, dname_table_node) table_tree_t;
+
+/*!
+ * \brief Structure holding tree together with dname ID counter.
+ */
+struct knot_dname_table {
+ unsigned int id_counter; /*!< ID counter (starts from 1) */
+ table_tree_t *tree; /*!< AVL tree */
+};
+
+typedef struct knot_dname_table knot_dname_table_t;
+
+/*!
+ * \brief Creates new empty domain name table.
+ *
+ * \retval Created table on success.
+ * \retval NULL on memory error.
+ */
+knot_dname_table_t *knot_dname_table_new();
+
+/*!
+ * \brief Finds name in the domain name table.
+ *
+ * \note Reference count to dname will be incremented, caller is responsible
+ * for releasing it.
+ *
+ * \param table Domain name table to be searched.
+ * \param dname Dname to be searched.
+ *
+ * \retval Pointer to found dname when dname is present in the table.
+ * \retval NULL when dname is not present.
+ */
+knot_dname_t *knot_dname_table_find_dname(const knot_dname_table_t *table,
+ knot_dname_t *dname);
+
+/*!
+ * \brief Adds domain name to domain name table.
+ *
+ * \param table Domain name table to be added to.
+ * \param dname Domain name to be added.
+ *
+ * \warning Function does not check for duplicates!
+ *
+ * \note This function encapsulates dname in a structure and saves it to a tree.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_ENOMEM when memory runs out.
+ */
+int knot_dname_table_add_dname(knot_dname_table_t *table,
+ knot_dname_t *dname);
+
+/*!
+ * \brief Adds domain name to domain name table and checks for duplicates.
+ *
+ * \param table Domain name table to be added to.
+ * \param dname Domain name to be added.
+ *
+ * \note This function encapsulates dname in a structure and saves it to a tree.
+ * \note If a duplicate is found, \a dname is replaced by the name from table.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_ENOMEM when memory runs out.
+ */
+int knot_dname_table_add_dname_check(knot_dname_table_t *table,
+ knot_dname_t **dname);
+
+/*!
+ * \brief Creates a shallow copy of the domain name table.
+ *
+ * Expects an existing knot_dname_table_t structure to be passed via \a to,
+ * and fills it with the same data (domain names) as the original. Actual
+ * tree nodes are created, but domain names are not copied (just referenced).
+ *
+ * \param from Original domain name table.
+ * \param to Copy of the domain name table.
+ */
+int knot_dname_table_shallow_copy(knot_dname_table_t *from,
+ knot_dname_table_t *to);
+
+/*!
+ * \brief Frees dname table without its nodes. Sets pointer to NULL.
+ *
+ * \param table Table to be freed.
+ */
+void knot_dname_table_free(knot_dname_table_t **table);
+
+/*!
+ * \brief Frees dname table and all its nodes (and release dnames in the nodes)
+ * Sets pointer to NULL.
+ *
+ * \param table Table to be freed.
+ */
+void knot_dname_table_deep_free(knot_dname_table_t **table);
+
+/*!
+ * \brief Frees dname table and all its nodes (including dnames in the nodes)
+ * Sets pointer to NULL.
+ *
+ * \param table Table to be freed.
+ */
+void knot_dname_table_destroy(knot_dname_table_t **table);
+
+/*!
+ * \brief Encapsulation of domain name table tree traversal function.
+ *
+ * \param table Table containing tree to be traversed.
+ * \param applied_function Function to be used to process nodes.
+ * \param data Data to be passed to processing function.
+ */
+void knot_dname_table_tree_inorder_apply(const knot_dname_table_t *table,
+ void (*applied_function)(knot_dname_t *dname,
+ void *data),
+ void *data);
+
+
+#endif // _KNOT_DNAME_TABLE_H_
+
+/*! @} */
+
diff --git a/src/libknot/zone/node.c b/src/libknot/zone/node.c
new file mode 100644
index 0000000..1d2f938
--- /dev/null
+++ b/src/libknot/zone/node.c
@@ -0,0 +1,906 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <urcu.h>
+
+#include "common.h"
+#include "zone/node.h"
+#include "rrset.h"
+#include "util/error.h"
+#include "common/skip-list.h"
+#include "common/tree.h"
+#include "util/debug.h"
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Returns the delegation point flag
+ *
+ * \param flags Flags to retrieve the flag from.
+ *
+ * \return A byte with only the delegation point flag set if it was set in
+ * \a flags.
+ */
+static inline uint8_t knot_node_flags_get_deleg(uint8_t flags)
+{
+ return flags & KNOT_NODE_FLAGS_DELEG;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Sets the delegation point flag.
+ *
+ * \param flags Flags to set the flag in.
+ */
+static inline void knot_node_flags_set_deleg(uint8_t *flags)
+{
+ *flags |= KNOT_NODE_FLAGS_DELEG;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Returns the non-authoritative node flag
+ *
+ * \param flags Flags to retrieve the flag from.
+ *
+ * \return A byte with only the non-authoritative node flag set if it was set in
+ * \a flags.
+ */
+static inline uint8_t knot_node_flags_get_nonauth(uint8_t flags)
+{
+ return flags & KNOT_NODE_FLAGS_NONAUTH;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Sets the non-authoritative node flag.
+ *
+ * \param flags Flags to set the flag in.
+ */
+static inline void knot_node_flags_set_nonauth(uint8_t *flags)
+{
+ *flags |= KNOT_NODE_FLAGS_NONAUTH;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Returns the old node flag
+ *
+ * \param flags Flags to retrieve the flag from.
+ *
+ * \return A byte with only the old node flag set if it was set in \a flags.
+ */
+static inline uint8_t knot_node_flags_get_old(uint8_t flags)
+{
+ return flags & KNOT_NODE_FLAGS_OLD;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Sets the old node flag.
+ *
+ * \param flags Flags to set the flag in.
+ */
+static inline void knot_node_flags_set_new(uint8_t *flags)
+{
+ *flags |= KNOT_NODE_FLAGS_NEW;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Returns the new node flag
+ *
+ * \param flags Flags to retrieve the flag from.
+ *
+ * \return A byte with only the new node flag set if it was set in \a flags.
+ */
+static inline uint8_t knot_node_flags_get_new(uint8_t flags)
+{
+ return flags & KNOT_NODE_FLAGS_NEW;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Sets the new node flag.
+ *
+ * \param flags Flags to set the flag in.
+ */
+static inline void knot_node_flags_set_old(uint8_t *flags)
+{
+ *flags |= KNOT_NODE_FLAGS_OLD;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static inline void knot_node_flags_clear_new(uint8_t *flags)
+{
+ *flags &= ~KNOT_NODE_FLAGS_NEW;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static inline void knot_node_flags_clear_old(uint8_t *flags)
+{
+ *flags &= ~KNOT_NODE_FLAGS_OLD;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Compares the two keys as RR types.
+ *
+ * \note This function may be used in data structures requiring generic
+ * comparation function.
+ *
+ * \param key1 First RR type.
+ * \param key2 Second RR type.
+ *
+ * \retval 0 if \a key1 is equal to \a key2.
+ * \retval < 0 if \a key1 is lower than \a key2.
+ * \retval > 0 if \a key1 is higher than \a key2.
+ */
+static int compare_rrset_types(void *rr1, void *rr2)
+{
+ knot_rrset_t *rrset1 = (knot_rrset_t *)rr1;
+ knot_rrset_t *rrset2 = (knot_rrset_t *)rr2;
+ return ((rrset1->type > rrset2->type) ? 1 :
+ (rrset1->type == rrset2->type) ? 0 : -1);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_node_zone_gen_is_new(const knot_node_t *node)
+{
+ assert(node->zone != NULL);
+ knot_zone_contents_t *cont = rcu_dereference(node->zone->contents);
+ assert(cont != NULL);
+ return knot_zone_contents_gen_is_new(cont);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_node_zone_gen_is_old(const knot_node_t *node)
+{
+ assert(node->zone != NULL);
+ knot_zone_contents_t *cont = rcu_dereference(node->zone->contents);
+ assert(cont != NULL);
+ return knot_zone_contents_gen_is_old(cont);
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_node_new(knot_dname_t *owner, knot_node_t *parent,
+ uint8_t flags)
+{
+ knot_node_t *ret = (knot_node_t *)calloc(1, sizeof(knot_node_t));
+ if (ret == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ /* Store reference to owner. */
+ knot_dname_retain(owner);
+ ret->owner = owner;
+ knot_node_set_parent(ret, parent);
+ ret->rrset_tree = gen_tree_new(compare_rrset_types);
+ ret->flags = flags;
+
+ assert(ret->children == 0);
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset,
+ int merge)
+{
+ int ret = 0;
+
+ if ((ret = (gen_tree_add(node->rrset_tree, rrset,
+ (merge) ? knot_rrset_merge : NULL))) < 0) {
+ dbg_node("Failed to add rrset to node->rrset_tree.\n");
+ return KNOT_ERROR;
+ }
+
+ if (ret >= 0) {
+ node->rrset_count += (ret > 0 ? 0 : 1);
+ return ret;
+ } else {
+ return KNOT_ERROR;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rrset_t *knot_node_rrset(const knot_node_t *node,
+ uint16_t type)
+{
+ assert(node != NULL);
+ assert(node->rrset_tree != NULL);
+ knot_rrset_t rrset;
+ rrset.type = type;
+ return (const knot_rrset_t *)gen_tree_find(node->rrset_tree, &rrset);
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_rrset_t *knot_node_get_rrset(knot_node_t *node, uint16_t type)
+{
+ knot_rrset_t rrset;
+ rrset.type = type;
+ return (knot_rrset_t *)gen_tree_find(node->rrset_tree, &rrset);
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_rrset_t *knot_node_remove_rrset(knot_node_t *node, uint16_t type)
+{
+ knot_rrset_t dummy_rrset;
+ dummy_rrset.type = type;
+ knot_rrset_t *rrset =
+ (knot_rrset_t *)gen_tree_find(node->rrset_tree, &dummy_rrset);
+ if (rrset != NULL) {
+ gen_tree_remove(node->rrset_tree, rrset);
+ node->rrset_count--;
+ }
+ return rrset;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_remove_all_rrsets(knot_node_t *node)
+{
+ // remove RRSets but do not delete them
+ gen_tree_clear(node->rrset_tree);
+ node->rrset_count = 0;
+
+}
+
+/*----------------------------------------------------------------------------*/
+
+short knot_node_rrset_count(const knot_node_t *node)
+{
+ return node->rrset_count;
+}
+
+/*----------------------------------------------------------------------------*/
+
+struct knot_node_save_rrset_arg {
+ knot_rrset_t **array;
+ size_t count;
+};
+
+static void save_rrset_to_array(void *node, void *data)
+{
+ knot_rrset_t *rrset = (knot_rrset_t *)node;
+ struct knot_node_save_rrset_arg *args =
+ (struct knot_node_save_rrset_arg *)data;
+ args->array[args->count++] = rrset;
+}
+
+knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node)
+{
+// knot_node_dump(node, 1);
+ if (node->rrset_count == 0) {
+ return NULL;
+ }
+ knot_rrset_t **rrsets = (knot_rrset_t **)malloc(
+ node->rrset_count * sizeof(knot_rrset_t *));
+ CHECK_ALLOC_LOG(rrsets, NULL);
+ struct knot_node_save_rrset_arg args;
+ args.array = rrsets;
+ args.count = 0;
+
+ gen_tree_apply_inorder(node->rrset_tree, save_rrset_to_array,
+ &args);
+
+ assert(args.count == node->rrset_count);
+
+ return rrsets;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_rrset_t **knot_node_rrsets(const knot_node_t *node)
+{
+ //knot_node_dump((knot_node_t *)node, (void*)1);
+ if (node->rrset_count == 0) {
+ return NULL;
+ }
+
+ knot_rrset_t **rrsets = (knot_rrset_t **)malloc(
+ node->rrset_count * sizeof(knot_rrset_t *));
+ CHECK_ALLOC_LOG(rrsets, NULL);
+ struct knot_node_save_rrset_arg args;
+ args.array = rrsets;
+ args.count = 0;
+
+ gen_tree_apply_inorder(node->rrset_tree, save_rrset_to_array,
+ &args);
+
+ assert(args.count == node->rrset_count);
+ assert(args.count);
+
+ return (const knot_rrset_t **)rrsets;
+
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_node_parent(const knot_node_t *node,
+ int check_version)
+{
+// assert(!check_version
+// || (node->zone != NULL && node->zone->contents != NULL));
+
+ knot_node_t *parent = node->parent;
+
+ if (check_version && node->zone != NULL) {
+ int new_gen = knot_node_zone_gen_is_new(node);
+// short ver = knot_node_zone_generation(node);
+
+ /*! \todo Remove, this will not be true during the reference
+ * fixing.
+ */
+// assert(new_gen || parent == NULL
+// || !knot_node_is_new(parent));
+
+ if (new_gen && parent != NULL) {
+ // we want the new node
+ assert(node->parent->new_node != NULL);
+ parent = parent->new_node;
+ }
+ }
+
+ return parent;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_parent(knot_node_t *node, knot_node_t *parent)
+{
+ // decrease number of children of previous parent
+ if (node->parent != NULL) {
+ --parent->children;
+ }
+ // set the parent
+ node->parent = parent;
+
+ // increase the count of children of the new parent
+ if (parent != NULL) {
+ ++parent->children;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+unsigned int knot_node_children(const knot_node_t *node)
+{
+ return node->children;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_node_previous(const knot_node_t *node,
+ int check_version)
+{
+ return knot_node_get_previous(node, check_version);
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_node_get_previous(const knot_node_t *node,
+ int check_version)
+{
+ assert(!check_version
+ || (node->zone != NULL && node->zone->contents != NULL));
+
+ knot_node_t *prev = node->prev;
+
+ if (check_version && prev != NULL) {
+ int new_gen = knot_node_zone_gen_is_new(node);
+ int old_gen = knot_node_zone_gen_is_old(node);
+// short ver = knot_node_zone_generation(node);
+
+ if (old_gen) { // we want old node
+ while (knot_node_is_new(prev)) {
+ prev = prev->prev;
+ }
+ assert(!knot_node_is_new(prev));
+ } else if (new_gen) { // we want new node
+ while (knot_node_is_old(prev)) {
+ if (prev->new_node) {
+ prev = prev->new_node;
+ } else {
+ prev = prev;
+ }
+ }
+ assert(knot_node_is_new(prev));
+ }
+ }
+
+ return prev;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_previous(knot_node_t *node, knot_node_t *prev)
+{
+ node->prev = prev;
+ if (prev != NULL) {
+ // set the prev pointer of the next node to the given node
+ if (prev->next != NULL) {
+ assert(prev->next->prev == prev);
+ prev->next->prev = node;
+ }
+ node->next = prev->next;
+ prev->next = node;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_node_nsec3_node(const knot_node_t *node,
+ int check_version)
+{
+ knot_node_t *nsec3_node = node->nsec3_node;
+ if (nsec3_node == NULL) {
+ return NULL;
+ }
+
+ if (check_version) {
+ int new_gen = knot_node_zone_gen_is_new(node);
+ int old_gen = knot_node_zone_gen_is_old(node);
+// short ver = knot_node_zone_generation(node);
+ assert(new_gen || !knot_node_is_new(nsec3_node));
+ if (old_gen && knot_node_is_new(nsec3_node)) {
+ return NULL;
+ } else if (new_gen && knot_node_is_old(nsec3_node)) {
+ nsec3_node = nsec3_node->new_node;
+ }
+ }
+
+ return nsec3_node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_nsec3_node(knot_node_t *node, knot_node_t *nsec3_node)
+{
+ node->nsec3_node = nsec3_node;
+ if (nsec3_node != NULL) {
+ nsec3_node->nsec3_referer = node;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_node_owner(const knot_node_t *node)
+{
+ return node->owner;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_dname_t *knot_node_get_owner(const knot_node_t *node)
+{
+ return node->owner;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_owner(knot_node_t *node, knot_dname_t* owner)
+{
+ if (node) {
+ /* Retain new owner and release old owner. */
+ knot_dname_retain(owner);
+ knot_dname_release(node->owner);
+ node->owner = owner;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_node_wildcard_child(const knot_node_t *node,
+ int check_version)
+{
+ knot_node_t *w = node->wildcard_child;
+
+ if (check_version && w != 0) {
+ int new_gen = knot_node_zone_gen_is_new(node);
+ int old_gen = knot_node_zone_gen_is_old(node);
+// short ver = knot_node_zone_generation(node);
+
+ if (old_gen && knot_node_is_new(w)) {
+ return NULL;
+ } else if (new_gen && knot_node_is_old(w)) {
+ assert(w->new_node != NULL);
+ w = w->new_node;
+ }
+ }
+
+ return w;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_wildcard_child(knot_node_t *node,
+ knot_node_t *wildcard_child)
+{
+ node->wildcard_child = wildcard_child;
+// assert(wildcard_child->parent == node);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_node_current(const knot_node_t *node)
+{
+ if (node == NULL || node->zone == NULL
+ || knot_zone_contents(node->zone) == NULL) {
+ return node;
+ }
+
+ int new_gen = knot_node_zone_gen_is_new(node);
+ int old_gen = knot_node_zone_gen_is_old(node);
+// short ver = knot_node_zone_generation(node);
+
+ if (old_gen && knot_node_is_new(node)) {
+ return NULL;
+ } else if (new_gen && knot_node_is_old(node)) {
+ assert(node->new_node != NULL);
+ return node->new_node;
+ }
+ return node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_node_get_current(knot_node_t *node)
+{
+ if (node == NULL || node->zone == NULL
+ || knot_zone_contents(node->zone) == NULL) {
+ return node;
+ }
+
+ int new_gen = knot_node_zone_gen_is_new(node);
+ int old_gen = knot_node_zone_gen_is_old(node);
+// short ver = knot_node_zone_generation(node);
+
+ if (old_gen && knot_node_is_new(node)) {
+ return NULL;
+ } else if (new_gen && knot_node_is_old(node)) {
+ assert(node->new_node != NULL);
+ return node->new_node;
+ }
+
+ assert((old_gen && knot_node_is_old(node))
+ || (new_gen && knot_node_is_new(node))
+ || (!old_gen && !new_gen));
+
+ return node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_node_new_node(const knot_node_t *node)
+{
+ return node->new_node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_node_get_new_node(const knot_node_t *node)
+{
+ return node->new_node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_new_node(knot_node_t *node,
+ knot_node_t *new_node)
+{
+ node->new_node = new_node;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_zone(knot_node_t *node, knot_zone_t *zone)
+{
+ node->zone = zone;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_update_ref(knot_node_t **ref)
+{
+ if (*ref != NULL && knot_node_is_old(*ref)) {
+ *ref = (*ref)->new_node;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_update_refs(knot_node_t *node)
+{
+ /* CLEANUP */
+ /* OMG! */
+ // reference to previous node
+ knot_node_update_ref(&node->prev);
+// if (node->prev && knot_node_is_old(node->prev)) {
+// assert(node->prev->new_node != NULL);
+// node->prev = node->prev->new_node;
+// }
+
+ // reference to next node
+ knot_node_update_ref(&node->next);
+// if (node->next && knot_node_is_old(node->next)) {
+// assert(node->next->new_node != NULL);
+// node->next = node->next->new_node;
+// }
+
+ // reference to parent
+// if (node->parent && knot_node_is_old(node->parent)) {
+// assert(node->parent->new_node != NULL);
+// // do not use the API function to set parent, so that children count
+// // is not changed
+// //knot_node_set_parent(node, node->parent->new_node);
+// node->parent = node->parent->new_node;
+// }
+ knot_node_update_ref(&node->parent);
+
+ // reference to wildcard child
+ knot_node_update_ref(&node->wildcard_child);
+// if (node->wildcard_child && knot_node_is_old(node->wildcard_child)) {
+// assert(node->wildcard_child->new_node != NULL);
+// node->wildcard_child = node->wildcard_child->new_node;
+// }
+
+ // reference to NSEC3 node
+ knot_node_update_ref(&node->nsec3_node);
+// if (node->nsec3_node && knot_node_is_old(node->nsec3_node)) {
+// assert(node->nsec3_node->new_node != NULL);
+// node->nsec3_node = node->nsec3_node->new_node;
+// }
+
+ // reference to NSEC3 referrer
+ knot_node_update_ref(&node->nsec3_referer);
+// if (node->nsec3_referer && knot_node_is_old(node->nsec3_referer)) {
+// assert(node->nsec3_referer->new_node != NULL);
+// node->nsec3_referer = node->nsec3_referer->new_node;
+// }
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_deleg_point(knot_node_t *node)
+{
+ knot_node_flags_set_deleg(&node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_node_is_deleg_point(const knot_node_t *node)
+{
+ return knot_node_flags_get_deleg(node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_non_auth(knot_node_t *node)
+{
+ knot_node_flags_set_nonauth(&node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_node_is_non_auth(const knot_node_t *node)
+{
+ return knot_node_flags_get_nonauth(node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_node_is_auth(const knot_node_t *node)
+{
+ return (node->flags == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_node_is_new(const knot_node_t *node)
+{
+ return knot_node_flags_get_new(node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_node_is_old(const knot_node_t *node)
+{
+ return knot_node_flags_get_old(node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_new(knot_node_t *node)
+{
+ knot_node_flags_set_new(&node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_set_old(knot_node_t *node)
+{
+ knot_node_flags_set_old(&node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_clear_new(knot_node_t *node)
+{
+ knot_node_flags_clear_new(&node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_clear_old(knot_node_t *node)
+{
+ knot_node_flags_clear_old(&node->flags);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void knot_node_free_rrsets_from_tree(void *item, void *data)
+{
+ if (item == NULL) {
+ return;
+ }
+
+ knot_rrset_t *rrset = (knot_rrset_t *)(item);
+ knot_rrset_deep_free(&rrset, 0, 1, *((int *)data));
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames)
+{
+ /* CLEANUP */
+// knot_rrset_t **rrsets = knot_node_get_rrsets(node);
+// for (int i = 0; i < node->rrset_count; i++) {
+// knot_rrset_deep_free(&(rrsets[i]), 0, 1, free_rdata_dnames);
+// }
+
+// free(rrsets);
+
+ char *name = knot_dname_to_str(node->owner);
+ free(name);
+
+ gen_tree_destroy(&node->rrset_tree, knot_node_free_rrsets_from_tree,
+ (void *)&free_rdata_dnames);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_node_free(knot_node_t **node, int free_owner, int fix_refs)
+{
+ if (node == NULL || *node == NULL) {
+ return;
+ }
+
+ dbg_node("Freeing node.\n");
+ if ((*node)->rrset_tree != NULL) {
+ dbg_node("Freeing RRSets.\n");
+ gen_tree_destroy(&(*node)->rrset_tree, NULL, NULL);
+ }
+
+ /*! \todo Always release owner? */
+ //if (free_owner) {
+ dbg_node("Releasing owner.\n");
+ knot_dname_release((*node)->owner);
+ //}
+
+ // check nodes referencing this node and fix the references
+
+ if (fix_refs) {
+ // previous node
+ dbg_node("Checking previous.\n");
+ if ((*node)->prev && (*node)->prev->next == (*node)) {
+ (*node)->prev->next = (*node)->next;
+ }
+
+ dbg_node("Checking next.\n");
+ if ((*node)->next && (*node)->next->prev == (*node)) {
+ (*node)->next->prev = (*node)->prev;
+ }
+
+ // NSEC3 node
+ dbg_node("Checking NSEC3.\n");
+ if ((*node)->nsec3_node
+ && (*node)->nsec3_node->nsec3_referer == (*node)) {
+ (*node)->nsec3_node->nsec3_referer = NULL;
+ }
+
+ dbg_node("Checking NSEC3 ref.\n");
+ if ((*node)->nsec3_referer
+ && (*node)->nsec3_referer->nsec3_node == (*node)) {
+ (*node)->nsec3_referer->nsec3_node = NULL;
+ }
+
+ // wildcard child node
+ dbg_node("Checking parent's wildcard child.\n");
+ if ((*node)->parent
+ && (*node)->parent->wildcard_child == (*node)) {
+ (*node)->parent->wildcard_child = NULL;
+ }
+
+ // fix parent's children count
+ if ((*node)->parent) {
+ --(*node)->parent->children;
+ }
+ }
+
+ free(*node);
+ *node = NULL;
+
+ dbg_node("Done.\n");
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_node_compare(knot_node_t *node1, knot_node_t *node2)
+{
+ return knot_dname_compare(node1->owner, node2->owner);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to)
+{
+ // create new node
+ *to = knot_node_new(from->owner, from->parent, from->flags);
+ if (*to == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ /* Free old rrset_tree, as it will be replaced by shallow copy. */
+ gen_tree_destroy(&(*to)->rrset_tree, 0, 0);
+
+ // copy references
+ // do not use the API function to set parent, so that children count
+ // is not changed
+ memcpy(*to, from, sizeof(knot_node_t));
+
+ // copy RRSets
+ // copy the skip list with the old references
+ /* CLEANUP */
+ (*to)->rrset_tree = gen_tree_shallow_copy(from->rrset_tree);
+// assert((*to)->rrset_tree != from->rrset_tree);
+// (*to)->rrsets = skip_copy_list(from->rrsets);
+ if ((*to)->rrset_tree == NULL) {
+ free(*to);
+ *to = NULL;
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
diff --git a/src/libknot/zone/node.h b/src/libknot/zone/node.h
new file mode 100644
index 0000000..fcb612d
--- /dev/null
+++ b/src/libknot/zone/node.h
@@ -0,0 +1,436 @@
+/*!
+ * \file node.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Structure representing one node in domain name tree and API for
+ * manipulating it.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_NODE_H_
+#define _KNOT_NODE_H_
+
+#include "dname.h"
+#include "common/skip-list.h"
+#include "rrset.h"
+#include "common/tree.h"
+#include "common/general-tree.h"
+
+struct knot_zone;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Structure representing one node in a domain name tree, i.e. one domain
+ * name in a zone.
+ *
+ * RRSets are ordered by type and stored in a skip-list to allow fast lookup.
+ */
+struct knot_node {
+ knot_dname_t *owner; /*!< Domain name being the owner of this node. */
+ struct knot_node *parent; /*!< Parent node in the name hierarchy. */
+
+ /*! \brief Type-ordered list of RRSets belonging to this node. */
+ general_tree_t *rrset_tree;
+
+ unsigned short rrset_count; /*!< Number of RRSets stored in the node. */
+
+ /*! \brief Wildcard node being the direct descendant of this node. */
+ struct knot_node *wildcard_child;
+
+ /*!
+ * \brief Previous node in canonical order.
+ *
+ * Only authoritative nodes or delegation points are referenced by this,
+ * as only they may contain NSEC records needed for authenticating
+ * negative answers.
+ */
+ struct knot_node *prev;
+
+ struct knot_node *next;
+
+ /*!
+ * \brief NSEC3 node corresponding to this node.
+ *
+ * Such NSEC3 node has owner in form of the hashed domain name of this
+ * node prepended as a single label to the zone name.
+ */
+ struct knot_node *nsec3_node;
+
+ struct knot_node *nsec3_referer;
+
+ /*!
+ * \brief Various flags.
+ *
+ * Currently only two:
+ * 0x01 - node is a delegation point
+ * 0x02 - node is non-authoritative (under a delegation point)
+ * 0x80 - node is old and will be removed (during update)
+ * 0x40 - node is new, should not be used while zone is old
+ */
+ uint8_t flags;
+
+ struct knot_node *new_node;
+
+ unsigned int children;
+
+ /*!
+ * \brief Generation of node to be used.
+ *
+ * If set to 0, the old node will be used. Otherwise new nodes will
+ * be used. This applies when getting some referenced node.
+
+ */
+// short **generation;
+
+ struct knot_zone *zone;
+};
+
+typedef struct knot_node knot_node_t;
+
+/*----------------------------------------------------------------------------*/
+/*! \brief Flags used to mark nodes with some property. */
+typedef enum {
+ /*! \brief Node is a delegation point (i.e. marking a zone cut). */
+ KNOT_NODE_FLAGS_DELEG = (uint8_t)0x01,
+ /*! \brief Node is not authoritative (i.e. below a zone cut). */
+ KNOT_NODE_FLAGS_NONAUTH = (uint8_t)0x02,
+ /*! \brief Node is old and will be removed (during update). */
+ KNOT_NODE_FLAGS_OLD = (uint8_t)0x80,
+ /*! \brief Node is new and should not be used while zoen is old. */
+ KNOT_NODE_FLAGS_NEW = (uint8_t)0x40
+} knot_node_flags_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates and initializes new node structure.
+ *
+ * \todo Owner reference counter will be increased.
+ *
+ * \param owner Owner of the created node.
+ * \param parent Parent of the created node.
+ * \param flags Document me.
+ *
+ * \todo Document missing parameters.
+ *
+ * \return Newly created node or NULL if an error occured.
+ */
+knot_node_t *knot_node_new(knot_dname_t *owner, knot_node_t *parent,
+ uint8_t flags);
+
+/*!
+ * \brief Adds an RRSet to the node.
+ *
+ * \param node Node to add the RRSet to.
+ * \param rrset RRSet to add.
+ *
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_ERROR if the RRSet could not be inserted.
+ */
+int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset,
+ int merge);
+
+/*!
+ * \brief Returns the RRSet of the given type from the node.
+ *
+ * \param node Node to get the RRSet from.
+ * \param type Type of the RRSet to retrieve.
+ *
+ * \return RRSet from node \a node having type \a type, or NULL if no such
+ * RRSet exists in this node.
+ */
+const knot_rrset_t *knot_node_rrset(const knot_node_t *node,
+ uint16_t type);
+
+/*!
+ * \brief Returns the RRSet of the given type from the node (non-const version).
+ *
+ * \param node Node to get the RRSet from.
+ * \param type Type of the RRSet to retrieve.
+ *
+ * \return RRSet from node \a node having type \a type, or NULL if no such
+ * RRSet exists in this node.
+ */
+knot_rrset_t *knot_node_get_rrset(knot_node_t *node, uint16_t type);
+
+knot_rrset_t *knot_node_remove_rrset(knot_node_t *node, uint16_t type);
+
+void knot_node_remove_all_rrsets(knot_node_t *node);
+
+/*!
+ * \brief Returns number of RRSets in the node.
+ *
+ * \param node Node to get the RRSet count from.
+ *
+ * \return Number of RRSets in \a node.
+ */
+short knot_node_rrset_count(const knot_node_t *node);
+
+/*!
+ * \brief Returns all RRSets from the node.
+ *
+ * \param node Node to get the RRSets from.
+ *
+ * \return Newly allocated array of RRSets or NULL if an error occured.
+ */
+knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node);
+
+/*!
+ * \brief Returns all RRSets from the node.
+ *
+ * \note This function is identical to knot_node_get_rrsets(), only it returns
+ * non-modifiable data.
+ *
+ * \param node Node to get the RRSets from.
+ *
+ * \return Newly allocated array of RRSets or NULL if an error occured.
+ */
+const knot_rrset_t **knot_node_rrsets(const knot_node_t *node);
+
+/*!
+ * \brief Returns the parent of the node.
+ *
+ * \param node Node to get the parent of.
+ *
+ * \return Parent node of the given node or NULL if no parent has been set (e.g.
+ * node in a zone apex has no parent).
+ */
+const knot_node_t *knot_node_parent(const knot_node_t *node,
+ int check_version);
+
+/*!
+ * \brief Sets the parent of the node.
+ *
+ * \param node Node to set the parent of.
+ * \param parent Parent to set to the node.
+ */
+void knot_node_set_parent(knot_node_t *node, knot_node_t *parent);
+
+unsigned int knot_node_children(const knot_node_t *node);
+
+/*!
+ * \brief Returns the previous authoritative node or delegation point in
+ * canonical order or the first node in zone.
+ *
+ * \param node Node to get the previous node of.
+ *
+ * \return Previous authoritative node or delegation point in canonical order or
+ * the first node in zone if \a node is the last node in zone.
+ * \retval NULL if previous node is not set.
+ */
+const knot_node_t *knot_node_previous(const knot_node_t *node,
+ int check_version);
+
+/*!
+ * \brief Returns the previous authoritative node or delegation point in
+ * canonical order or the first node in zone.
+ *
+ * \note This function is identical to knot_node_previous() except that it
+ * returns non-const node.
+ *
+ * \param node Node to get the previous node of.
+ *
+ * \return Previous authoritative node or delegation point in canonical order or
+ * the first node in zone if \a node is the last node in zone.
+ * \retval NULL if previous node is not set.
+ */
+knot_node_t *knot_node_get_previous(const knot_node_t *node,
+ int check_version);
+
+/*!
+ * \brief Sets the previous node of the given node.
+ *
+ * \param node Node to set the previous node to.
+ * \param prev Previous node to set.
+ */
+void knot_node_set_previous(knot_node_t *node, knot_node_t *prev);
+
+/*!
+ * \brief Returns the NSEC3 node corresponding to the given node.
+ *
+ * \param node Node to get the NSEC3 node for.
+ *
+ * \return NSEC3 node corresponding to \a node (i.e. node with owner name
+ * created by concatenating the hash of owner domain name of \a node
+ * and the name of the zone \a node belongs to).
+ * \retval NULL if the NSEC3 node is not set.
+ */
+const knot_node_t *knot_node_nsec3_node(const knot_node_t *node,
+ int check_version);
+
+/*!
+ * \brief Sets the corresponding NSEC3 node of the given node.
+ *
+ * \param node Node to set the NSEC3 node to.
+ * \param nsec3_node NSEC3 node to set.
+ */
+void knot_node_set_nsec3_node(knot_node_t *node, knot_node_t *nsec3_node);
+
+/*!
+ * \brief Returns the owner of the node.
+ *
+ * \param node Node to get the owner of.
+ *
+ * \return Owner of the given node.
+ */
+const knot_dname_t *knot_node_owner(const knot_node_t *node);
+
+/*!
+ * \todo Document me.
+ */
+knot_dname_t *knot_node_get_owner(const knot_node_t *node);
+
+/*!
+ * \brief Set node owner to specified dname.
+ *
+ * Previous owner will be replaced if exist.
+ *
+ * \param node Specified node.
+ * \param owner New owner dname.
+ */
+void knot_node_set_owner(knot_node_t *node, knot_dname_t* owner);
+
+/*!
+ * \brief Returns the wildcard child of the node.
+ *
+ * \param node Node to get the owner of.
+ *
+ * \return Wildcard child of the given node or NULL if it has none.
+ */
+const knot_node_t *knot_node_wildcard_child(const knot_node_t *node,
+ int check_version);
+
+/*!
+ * \brief Sets the wildcard child of the node.
+ *
+ * \param node Node to set the wildcard child of.
+ * \param wildcard_child Wildcard child of the node.
+ */
+void knot_node_set_wildcard_child(knot_node_t *node,
+ knot_node_t *wildcard_child);
+
+const knot_node_t *knot_node_current(const knot_node_t *node);
+
+knot_node_t *knot_node_get_current(knot_node_t *node);
+
+const knot_node_t *knot_node_new_node(const knot_node_t *node);
+
+knot_node_t *knot_node_get_new_node(const knot_node_t *node);
+
+void knot_node_set_new_node(knot_node_t *node,
+ knot_node_t *new_node);
+
+void knot_node_set_zone(knot_node_t *node, struct knot_zone *zone);
+
+void knot_node_update_ref(knot_node_t **ref);
+
+void knot_node_update_refs(knot_node_t *node);
+
+/*!
+ * \brief Mark the node as a delegation point.
+ *
+ * \param node Node to mark as a delegation point.
+ */
+void knot_node_set_deleg_point(knot_node_t *node);
+
+/*!
+ * \brief Checks if the node is a delegation point.
+ *
+ * \param node Node to check.
+ *
+ * \retval <> 0 if \a node is marked as delegation point.
+ * \retval 0 otherwise.
+ */
+int knot_node_is_deleg_point(const knot_node_t *node);
+
+/*!
+ * \brief Mark the node as non-authoritative.
+ *
+ * \param node Node to mark as non-authoritative.
+ */
+void knot_node_set_non_auth(knot_node_t *node);
+
+/*!
+ * \brief Checks if the node is non-authoritative.
+ *
+ * \param node Node to check.
+ *
+ * \retval <> 0 if \a node is marked as non-authoritative.
+ * \retval 0 otherwise.
+ */
+int knot_node_is_non_auth(const knot_node_t *node);
+
+int knot_node_is_auth(const knot_node_t *node);
+
+int knot_node_is_new(const knot_node_t *node);
+
+int knot_node_is_old(const knot_node_t *node);
+
+void knot_node_set_new(knot_node_t *node);
+
+void knot_node_set_old(knot_node_t *node);
+
+void knot_node_clear_new(knot_node_t *node);
+
+void knot_node_clear_old(knot_node_t *node);
+
+/*!
+ * \brief Destroys the RRSets within the node structure.
+ *
+ * \param node Node to be destroyed.
+ * \param free_rdata_dnames Set to <> 0 if you want to delete ALL domain names
+ * present in RDATA. Set to 0 otherwise. (See
+ * knot_rdata_deep_free().)
+ */
+void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames);
+
+/*!
+ * \brief Destroys the node structure.
+ *
+ * Does not destroy the RRSets within the node.
+ * Also sets the given pointer to NULL.
+ *
+ * \param node Node to be destroyed.
+ * \param free_owner Set to 0 if you do not want the owner domain name to be
+ * destroyed also. Set to <> 0 otherwise.
+ * \param fix_refs
+ *
+ * \todo Document missing parameters.
+ */
+void knot_node_free(knot_node_t **node, int free_owner, int fix_refs);
+
+/*!
+ * \brief Compares two nodes according to their owner.
+ *
+ * \param node1 First node.
+ * \param node2 Second node.
+ *
+ * \retval < 0 if \a node1 goes before \a node2 according to canonical order
+ * of their owner names.
+ * \retval 0 if they are equal.
+ * \retval > 0 if \a node1 goes after \a node2.
+ */
+int knot_node_compare(knot_node_t *node1, knot_node_t *node2);
+
+int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to);
+
+#endif /* _KNOT_NODE_H_ */
+
+/*! @} */
diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c
new file mode 100644
index 0000000..d550728
--- /dev/null
+++ b/src/libknot/zone/zone-contents.c
@@ -0,0 +1,2396 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "zone/zone-contents.h"
+#include "util/error.h"
+#include "util/debug.h"
+#include "common/base32hex.h"
+#include "consts.h"
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+
+typedef struct {
+ void (*func)(knot_node_t *, void *);
+ void *data;
+} knot_zone_tree_func_t;
+
+typedef struct {
+ knot_node_t *first_node;
+ knot_zone_contents_t *zone;
+ knot_node_t *previous_node;
+ int check_ver;
+} knot_zone_adjust_arg_t;
+
+/*----------------------------------------------------------------------------*/
+
+static void knot_zone_tree_apply(knot_zone_tree_node_t *node,
+ void *data)
+{
+ if (node == NULL || data == NULL) {
+ return;
+ }
+
+ knot_zone_tree_func_t *f = (knot_zone_tree_func_t *)data;
+ f->func(node->node, f->data);
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Checks if the given node can be inserted into the given zone.
+ *
+ * Checks if both the arguments are non-NULL and if the owner of the node
+ * belongs to the zone (i.e. is a subdomain of the zone apex).
+ *
+ * \param zone Zone to which the node is going to be inserted.
+ * \param node Node to check.
+ *
+ * \retval KNOT_EOK if both arguments are non-NULL and the node belongs to the
+ * zone.
+ * \retval KNOT_EBADARG if either of the arguments is NULL.
+ * \retval KNOT_EBADZONE if the node does not belong to the zone.
+ */
+static int knot_zone_contents_check_node(
+ const knot_zone_contents_t *contents, const knot_node_t *node)
+{
+ if (contents == NULL || node == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // assert or just check??
+ assert(contents->apex != NULL);
+
+ if (!knot_dname_is_subdomain(node->owner,
+ knot_node_owner(contents->apex))) {
+dbg_zone_exec(
+ char *node_owner = knot_dname_to_str(knot_node_owner(node));
+ char *apex_owner = knot_dname_to_str(contents->apex->owner);
+ dbg_zone("zone: Trying to insert foreign node to a "
+ "zone. Node owner: %s, zone apex: %s\n",
+ node_owner, apex_owner);
+ free(node_owner);
+ free(apex_owner);
+);
+ return KNOT_EBADZONE;
+ }
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Destroys all RRSets in a node.
+ *
+ * This function is designed to be used in the tree-iterating functions.
+ *
+ * \param node Node to destroy RRSets from.
+ * \param data Unused parameter.
+ */
+static void knot_zone_contents_destroy_node_rrsets_from_tree(
+ knot_zone_tree_node_t *tnode, void *data)
+{
+ assert(tnode != NULL);
+ assert(tnode->node != NULL);
+
+ int free_rdata_dnames = (int)((intptr_t)data);
+ knot_node_free_rrsets(tnode->node, free_rdata_dnames);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Destroys node owner.
+ *
+ * This function is designed to be used in the tree-iterating functions.
+ *
+ * \param node Node to destroy the owner of.
+ * \param data Unused parameter.
+ */
+static void knot_zone_contents_destroy_node_owner_from_tree(
+ knot_zone_tree_node_t *tnode, void *data)
+{
+ assert(tnode != NULL);
+ assert(tnode->node != NULL);
+
+ UNUSED(data);
+ /*!< \todo change completely! */
+ knot_node_free(&tnode->node, 0, 0);
+}
+
+/*!
+ * \brief Finds and sets wildcard child for given node's owner.
+ *
+ * \param zone Current zone.
+ * \param node Node to be used.
+ */
+static void find_and_set_wildcard_child(knot_zone_contents_t *zone,
+ knot_node_t *node)
+{
+ knot_dname_t *chopped = knot_dname_left_chop(node->owner);
+ assert(chopped);
+ knot_node_t *wildcard_parent;
+ wildcard_parent =
+ knot_zone_contents_get_node(zone, chopped);
+
+ knot_dname_free(&chopped);
+
+ assert(wildcard_parent); /* it *has* to be there */
+
+ knot_node_set_wildcard_child(wildcard_parent, node);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adjusts one RDATA item by replacing domain name by one present in the
+ * zone.
+ *
+ * This function tries to find the domain name in the zone. If the name is not
+ * in the zone, it does nothing. If it is there, it destroys the domain name
+ * stored in the RDATA item and replaces it by pointer to the domain name from
+ * the zone.
+ *
+ * \warning Call this function only with RDATA items which store domain names,
+ * otherwise the behaviour is undefined.
+ *
+ * \param rdata RDATA where the item is located.
+ * \param zone Zone to which the RDATA belongs.
+ * \param pos Position of the RDATA item in the RDATA.
+ */
+static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata,
+ knot_zone_contents_t *zone,
+ knot_node_t *node,
+ int pos)
+{
+ return;
+ const knot_rdata_item_t *dname_item
+ = knot_rdata_item(rdata, pos);
+
+ assert(dname_item);
+
+ if (dname_item != NULL) {
+ knot_dname_t *dname = dname_item->dname;
+ const knot_node_t *n = NULL;
+ const knot_node_t *closest_encloser = NULL;
+ const knot_node_t *prev = NULL;
+
+ if (knot_dname_is_wildcard(dname)) {
+ find_and_set_wildcard_child(zone, node);
+ }
+
+ int ret = knot_zone_contents_find_dname(zone, dname, &n,
+ &closest_encloser, &prev);
+
+ // n = knot_zone_find_node(zone, dname);
+
+ if (ret == KNOT_EBADARG || ret == KNOT_EBADZONE) {
+ // TODO: do some cleanup if needed
+ return;
+ }
+
+ assert(ret != KNOT_ZONE_NAME_FOUND
+ || n == closest_encloser);
+
+ if (ret != KNOT_ZONE_NAME_FOUND
+ && (closest_encloser != NULL)) {
+ dbg_zone("Saving closest encloser to RDATA.\n");
+ // save pointer to the closest encloser
+ knot_rdata_item_t *item =
+ knot_rdata_get_item(rdata, pos);
+ assert(item->dname != NULL);
+ assert(item->dname->node == NULL);
+ //skip_insert(list, (void *)item->dname,
+ // (void *)closest_encloser->owner, NULL);
+ item->dname->node = closest_encloser->owner->node;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adjusts all RDATA in the given RRSet by replacing domain names by ones
+ * present in the zone.
+ *
+ * This function selects the RDATA items containing a domain name (according to
+ * RR type descriptor of the RRSet's type and adjusts the item using
+ * knot_zone_adjust_rdata_item().
+ *
+ * \param rrset RRSet to adjust RDATA in.
+ * \param zone Zone to which the RRSet belongs.
+ */
+static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset,
+ knot_zone_contents_t *zone,
+ knot_node_t *node)
+{
+ uint16_t type = knot_rrset_type(rrset);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ assert(desc);
+
+ knot_rdata_t *rdata_first = knot_rrset_get_rdata(rrset);
+ knot_rdata_t *rdata = rdata_first;
+
+ if (rdata == NULL) {
+ return;
+ }
+
+ while (rdata->next != rdata_first) {
+ for (int i = 0; i < rdata->count; ++i) {
+ if (desc->wireformat[i]
+ == KNOT_RDATA_WF_COMPRESSED_DNAME
+ || desc->wireformat[i]
+ == KNOT_RDATA_WF_UNCOMPRESSED_DNAME
+ || desc->wireformat[i]
+ == KNOT_RDATA_WF_LITERAL_DNAME) {
+ dbg_zone("Adjusting domain name at "
+ "position %d of RDATA of record with owner "
+ "%s and type %s.\n",
+ i, rrset->owner->name,
+ knot_rrtype_to_string(type));
+
+ knot_zone_contents_adjust_rdata_item(rdata,
+ zone,
+ node,
+ i);
+ }
+ }
+ rdata = rdata->next;
+ }
+
+ for (int i = 0; i < rdata->count; ++i) {
+ if (desc->wireformat[i]
+ == KNOT_RDATA_WF_COMPRESSED_DNAME
+ || desc->wireformat[i]
+ == KNOT_RDATA_WF_UNCOMPRESSED_DNAME
+ || desc->wireformat[i]
+ == KNOT_RDATA_WF_LITERAL_DNAME) {
+ dbg_zone("Adjusting domain name at "
+ "position %d of RDATA of record with owner "
+ "%s and type %s.\n",
+ i, rrset->owner->name,
+ knot_rrtype_to_string(type));
+
+ knot_zone_contents_adjust_rdata_item(rdata, zone,
+ node, i);
+ }
+ }
+
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adjusts all RRSets in the given node by replacing domain names in
+ * RDATA by ones present in the zone.
+ *
+ * This function just calls knot_zone_adjust_rdata_in_rrset() for all RRSets
+ * in the node (including all RRSIG RRSets).
+ *
+ * \param node Zone node to adjust the RRSets in.
+ * \param zone Zone to which the node belongs.
+ */
+static void knot_zone_contents_adjust_rrsets(knot_node_t *node,
+ knot_zone_contents_t *zone)
+{
+ //return;
+ knot_rrset_t **rrsets = knot_node_get_rrsets(node);
+ short count = knot_node_rrset_count(node);
+
+ assert(count == 0 || rrsets != NULL);
+
+ for (int r = 0; r < count; ++r) {
+ assert(rrsets[r] != NULL);
+ dbg_zone("Adjusting next RRSet.\n");
+ knot_zone_contents_adjust_rdata_in_rrset(rrsets[r], zone,
+ node);
+ knot_rrset_t *rrsigs = rrsets[r]->rrsigs;
+ if (rrsigs != NULL) {
+ dbg_zone("Adjusting next RRSIGs.\n");
+ knot_zone_contents_adjust_rdata_in_rrset(rrsigs,
+ zone,
+ node);
+ }
+ }
+
+ free(rrsets);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adjusts zone node for faster query processing.
+ *
+ * - Adjusts RRSets in the node (see knot_zone_adjust_rrsets()).
+ * - Marks the node as delegation point or non-authoritative (below a zone cut)
+ * if applicable.
+ * - Stores reference to corresponding NSEC3 node if applicable.
+ *
+ * \param node Zone node to adjust.
+ * \param zone Zone the node belongs to.
+ */
+static void knot_zone_contents_adjust_node(knot_node_t *node,
+ knot_zone_contents_t *zone,
+ int check_ver)
+{
+
+dbg_zone_exec(
+ char *name = knot_dname_to_str(node->owner);
+ dbg_zone("----- Adjusting node %s -----\n", name);
+ free(name);
+);
+
+ // adjust domain names in RDATA
+ knot_zone_contents_adjust_rrsets(node, zone);
+
+dbg_zone_exec(
+ if (knot_node_parent(node, 1)) {
+ char *name = knot_dname_to_str(knot_node_owner(
+ knot_node_parent(node, check_ver)));
+ dbg_zone("Parent: %s\n", name);
+ dbg_zone("Parent is delegation point: %s\n",
+ knot_node_is_deleg_point(knot_node_parent(node, check_ver))
+ ? "yes" : "no");
+ dbg_zone("Parent is non-authoritative: %s\n",
+ knot_node_is_non_auth(knot_node_parent(node, check_ver))
+ ? "yes" : "no");
+ free(name);
+ } else {
+ dbg_zone("No parent!\n");
+ }
+);
+ // delegation point / non-authoritative node
+ if (knot_node_parent(node, check_ver)
+ && (knot_node_is_deleg_point(knot_node_parent(node, check_ver))
+ || knot_node_is_non_auth(knot_node_parent(node, check_ver)))) {
+ knot_node_set_non_auth(node);
+ } else if (knot_node_rrset(node, KNOT_RRTYPE_NS) != NULL
+ && node != zone->apex) {
+ knot_node_set_deleg_point(node);
+ }
+
+ // authorative node?
+// if (!knot_node_is_non_auth(node)) {
+ zone->node_count++;
+// }
+
+ // assure that owner has proper node
+ if (knot_dname_node(knot_node_owner(node), 0) == NULL) {
+ knot_dname_set_node(knot_node_get_owner(node), node);
+ knot_dname_set_node(knot_node_get_owner(node), node);
+ }
+
+ // NSEC3 node (only if NSEC3 tree is not empty)
+ const knot_node_t *prev;
+ const knot_node_t *nsec3;
+ int match = knot_zone_contents_find_nsec3_for_name(zone,
+ knot_node_owner(node),
+ &nsec3, &prev, check_ver);
+ if (match != KNOT_ZONE_NAME_FOUND) {
+ nsec3 = NULL;
+ }
+
+ knot_node_set_nsec3_node(node, (knot_node_t *)nsec3);
+
+ dbg_zone("Set flags to the node: \n");
+ dbg_zone("Delegation point: %s\n",
+ knot_node_is_deleg_point(node) ? "yes" : "no");
+ dbg_zone("Non-authoritative: %s\n",
+ knot_node_is_non_auth(node) ? "yes" : "no");
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adjusts zone node for faster query processing.
+ *
+ * This function is just a wrapper over knot_zone_adjust_node() to be used
+ * in tree-traversing functions.
+ *
+ * \param node Zone node to adjust.
+ * \param data Zone the node belongs to.
+ */
+static void knot_zone_contents_adjust_node_in_tree(
+ knot_zone_tree_node_t *tnode, void *data)
+{
+ assert(data != NULL);
+ assert(tnode != NULL);
+ assert(tnode->node != NULL);
+
+ knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data;
+ knot_node_t *node = tnode->node;
+ knot_node_set_previous(node, args->previous_node);
+ args->previous_node = node;
+ if (args->first_node == NULL) {
+ args->first_node = node;
+ }
+ knot_zone_contents_t *zone = args->zone;
+
+ knot_zone_contents_adjust_node(node, zone, args->check_ver);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Adjusts NSEC3 node for faster query processing.
+ *
+ * This function is just a wrapper over knot_zone_adjust_nsec3_node() to be
+ * used in tree-traversing functions.
+ *
+ * \param node Zone node to adjust.
+ * \param data Zone the node belongs to.
+ */
+static void knot_zone_contents_adjust_nsec3_node_in_tree(
+ knot_zone_tree_node_t *tnode, void *data)
+{
+ assert(data != NULL);
+ assert(tnode != NULL);
+ assert(tnode->node != NULL);
+
+ knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data;
+ knot_node_t *node = tnode->node;
+ knot_node_set_previous(node, args->previous_node);
+ args->previous_node = node;
+ if (args->first_node == NULL) {
+ args->first_node = node;
+ }
+
+ /* Not needed anymore. */
+// knot_zone_contents_t *zone = args->zone;
+// knot_zone_contents_adjust_nsec3_node(node, zone, 1);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates a NSEC3 hashed name for the given domain name.
+ *
+ * \note The zone's NSEC3PARAM record must be parsed prior to calling this
+ * function (see knot_zone_load_nsec3param()).
+ *
+ * \param zone Zone from which to take the NSEC3 parameters.
+ * \param name Domain name to hash.
+ * \param nsec3_name Hashed name.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENSEC3PAR
+ * \retval KNOT_ECRYPTO
+ * \retval KNOT_ERROR if an error occured while creating a new domain name
+ * from the hash or concatenating it with the zone name.
+ */
+static int knot_zone_contents_nsec3_name(const knot_zone_contents_t *zone,
+ const knot_dname_t *name,
+ knot_dname_t **nsec3_name)
+{
+ assert(nsec3_name != NULL);
+
+ *nsec3_name = NULL;
+
+ const knot_nsec3_params_t *nsec3_params =
+ knot_zone_contents_nsec3params(zone);
+
+ if (nsec3_params == NULL) {
+dbg_zone_exec(
+ char *n = knot_dname_to_str(zone->apex->owner);
+ dbg_zone("No NSEC3PARAM for zone %s.\n", n);
+ free(n);
+);
+ return KNOT_ENSEC3PAR;
+ }
+
+ uint8_t *hashed_name = NULL;
+ size_t hash_size = 0;
+
+dbg_zone_exec(
+ char *n = knot_dname_to_str(name);
+ dbg_zone("Hashing name %s.\n", n);
+ free(n);
+);
+
+ int res = knot_nsec3_sha1(nsec3_params, knot_dname_name(name),
+ knot_dname_size(name), &hashed_name,
+ &hash_size);
+
+ if (res != 0) {
+ char *n = knot_dname_to_str(name);
+ dbg_zone("Error while hashing name %s.\n", n);
+ free(n);
+ return KNOT_ECRYPTO;
+ }
+
+ dbg_zone("Hash: ");
+ dbg_zone_hex((char *)hashed_name, hash_size);
+ dbg_zone("\n");
+
+ char *name_b32 = NULL;
+ size_t size = base32hex_encode_alloc((char *)hashed_name, hash_size,
+ &name_b32);
+
+ if (size == 0) {
+ char *n = knot_dname_to_str(name);
+ dbg_zone("Error while encoding hashed name %s to "
+ "base32.\n", n);
+ free(n);
+ if (name_b32 != NULL) {
+ free(name_b32);
+ }
+ return KNOT_ECRYPTO;
+ }
+
+ assert(name_b32 != NULL);
+ free(hashed_name);
+
+ dbg_zone("Base32-encoded hash: %s\n", name_b32);
+
+ /* Will be returned to caller, make sure it is released after use. */
+ *nsec3_name = knot_dname_new_from_str(name_b32, size, NULL);
+
+ free(name_b32);
+
+ if (*nsec3_name == NULL) {
+ dbg_zone("Error while creating domain name for hashed"
+ " name.\n");
+ return KNOT_ERROR;
+ }
+
+ assert(zone->apex->owner != NULL);
+ knot_dname_t *ret = knot_dname_cat(*nsec3_name, zone->apex->owner);
+
+ if (ret == NULL) {
+ dbg_zone("Error while creating NSEC3 domain name for "
+ "hashed name.\n");
+ knot_dname_release(*nsec3_name);
+ return KNOT_ERROR;
+ }
+
+ assert(ret == *nsec3_name);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tries to find the given domain name in the zone tree.
+ *
+ * \param zone Zone to search in.
+ * \param name Domain name to find.
+ * \param node Found node.
+ * \param previous Previous node in canonical order (i.e. the one directly
+ * preceding \a name in canonical order, regardless if the name
+ * is in the zone or not).
+ *
+ * \retval <> 0 if the domain name was found. In such case \a node holds the
+ * zone node with \a name as its owner. \a previous is set
+ * properly.
+ * \retval 0 if the domain name was not found. \a node may hold any (or none)
+ * node. \a previous is set properly.
+ */
+static int knot_zone_contents_find_in_tree(knot_zone_tree_t *tree,
+ const knot_dname_t *name,
+ knot_node_t **node,
+ knot_node_t **previous)
+{
+ assert(tree != NULL);
+ assert(name != NULL);
+ assert(node != NULL);
+ assert(previous != NULL);
+
+ knot_node_t *found = NULL, *prev = NULL;
+// knot_node_t *found2 = NULL, *prev2 = NULL;
+
+ int exact_match = knot_zone_tree_get_less_or_equal(
+ tree, name, &found, &prev, 1);
+
+// assert(prev != NULL);
+ assert(exact_match >= 0);
+ *node = found;
+ *previous = prev;
+
+// if (prev == NULL) {
+// // either the returned node is the root of the tree, or it is
+// // the leftmost node in the tree; in both cases node was found
+// // set the previous node of the found node
+// assert(exact_match);
+// assert(found != NULL);
+// *previous = knot_node_get_previous(found, 1);
+// } else {
+// // otherwise check if the previous node is not an empty
+// // non-terminal
+// *previous = (knot_node_rrset_count(prev) == 0)
+// ? knot_node_get_previous(prev, 1)
+// : prev;
+// }
+
+ return exact_match;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void knot_zone_contents_node_to_hash(knot_zone_tree_node_t *tnode,
+ void *data)
+{
+ assert(tnode != NULL && tnode->node != NULL
+ && tnode->node->owner != NULL && data != NULL);
+
+ knot_node_t *node = tnode->node;
+
+ knot_zone_contents_t *zone = (knot_zone_contents_t *)data;
+ /*
+ * By the original approach, only authoritative nodes and delegation
+ * points should be added to the hash table, but currently, all nodes
+ * are being added when the zone is created (don't know why actually:),
+ * so we will do no distinction here neither.
+ */
+
+#ifdef USE_HASH_TABLE
+//dbg_zone_exec(
+// char *name = knot_dname_to_str(node->owner);
+// dbg_zone("Adding node with owner %s to hash table.\n", name);
+// free(name);
+//);
+ //assert(zone->table != NULL);
+ // add the node also to the hash table if authoritative, or deleg. point
+ if (zone->table != NULL
+ && ck_insert_item(zone->table,
+ (const char *)node->owner->name,
+ node->owner->size, (void *)node) != 0) {
+ dbg_zone("Error inserting node into hash table!\n");
+ }
+#endif
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_zone_contents_dnames_from_rdata_to_table(
+ knot_dname_table_t *table, knot_rdata_t *rdata,
+ knot_rrtype_descriptor_t *d)
+{
+ unsigned int count = knot_rdata_item_count(rdata);
+ int rc = 0;
+ assert(count <= d->length);
+ // for each RDATA item
+ for (unsigned int j = 0; j < count; ++j) {
+ if (d->wireformat[j]
+ == KNOT_RDATA_WF_COMPRESSED_DNAME
+ || d->wireformat[j]
+ == KNOT_RDATA_WF_UNCOMPRESSED_DNAME
+ || d->wireformat[j]
+ == KNOT_RDATA_WF_LITERAL_DNAME) {
+ dbg_zone("Saving dname from "
+ "rdata to dname table"
+ ".\n");
+ rc = knot_dname_table_add_dname_check(table,
+ &knot_rdata_get_item(rdata, j)->dname);
+ if (rc < 0) {
+ dbg_zone("Error: %s\n",
+ knot_strerror(rc));
+ return rc;
+ }
+ }
+ }
+
+ dbg_zone("RDATA OK.\n");
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_zone_contents_dnames_from_rrset_to_table(
+ knot_dname_table_t *table, knot_rrset_t *rrset, int replace_owner,
+ knot_dname_t *owner)
+{
+ assert(table != NULL && rrset != NULL && owner != NULL);
+
+ if (replace_owner) {
+ // discard the old owner and replace it with the new
+ knot_rrset_set_owner(rrset, owner);
+ }
+ dbg_zone("RRSet owner: %p\n", rrset->owner);
+
+ knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(
+ knot_rrset_type(rrset));
+ if (desc == NULL) {
+ // not recognized RR type, ignore
+ dbg_zone("RRSet type not recognized.\n");
+ return KNOT_EOK;
+ }
+ // for each RDATA in RRSet
+ knot_rdata_t *rdata = knot_rrset_get_rdata(rrset);
+ while (rdata != NULL) {
+ int rc = knot_zone_contents_dnames_from_rdata_to_table(table,
+ rdata, desc);
+ if (rc != KNOT_EOK) {
+ return rc;
+ }
+
+ rdata = knot_rrset_rdata_get_next(rrset, rdata);
+ }
+
+ dbg_zone("RRSet OK.\n");
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_zone_contents_dnames_from_node_to_table(
+ knot_dname_table_t *table, knot_node_t *node)
+{
+ /*
+ * Assuming that all the RRSets have the same owner as the node.
+ */
+
+ // insert owner
+ char *name = knot_dname_to_str(node->owner);
+ dbg_zone("Node owner before inserting to dname table: %p.\n",
+ node->owner);
+ dbg_zone("Node owner before inserting to dname table: %s.\n",
+ name);
+ free(name);
+ //knot_dname_t *old_owner = node->owner;
+ int rc = knot_dname_table_add_dname_check(table, &node->owner);
+ if (rc < 0) {
+ dbg_zone("Failed to add dname to dname table.\n");
+ return rc;
+ }
+ int replace_owner = (rc > 0);
+ dbg_zone("Node owner after inserting to dname table: %p.\n",
+ node->owner);
+ name = knot_dname_to_str(node->owner);
+ dbg_zone("Node owner after inserting to dname table: %s.\n",
+ name);
+ free(name);
+
+ knot_rrset_t **rrsets = knot_node_get_rrsets(node);
+ // for each RRSet
+ for (int i = 0; i < knot_node_rrset_count(node); ++i) {
+ dbg_zone("Inserting RRSets from node to table.\n");
+ rc = knot_zone_contents_dnames_from_rrset_to_table(table,
+ rrsets[i], replace_owner, node->owner);
+ if (rc != KNOT_EOK) {
+ return rc;
+ }
+ }
+
+ free(rrsets);
+
+ dbg_zone("Node OK\n");
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex,
+ uint node_count,
+ int use_domain_table,
+ struct knot_zone *zone)
+{
+ knot_zone_contents_t *contents = (knot_zone_contents_t *)
+ calloc(1, sizeof(knot_zone_contents_t));
+ if (contents == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+// printf("created cont: %p (%s)\n",
+// contents, knot_dname_to_str(apex->owner));
+
+ contents->apex = apex;
+ contents->zone = zone;
+ knot_node_set_zone(apex, zone);
+
+ dbg_zone("Creating tree for normal nodes.\n");
+ contents->nodes = malloc(sizeof(knot_zone_tree_t));
+ if (contents->nodes == NULL) {
+ ERR_ALLOC_FAILED;
+ goto cleanup;
+ }
+
+ dbg_zone("Creating tree for NSEC3 nodes.\n");
+ contents->nsec3_nodes = malloc(sizeof(knot_zone_tree_t));
+ if (contents->nsec3_nodes == NULL) {
+ ERR_ALLOC_FAILED;
+ goto cleanup;
+ }
+
+ if (use_domain_table) {
+ dbg_zone("Creating domain name table.\n");
+ contents->dname_table = knot_dname_table_new();
+ if (contents->dname_table == NULL) {
+ ERR_ALLOC_FAILED;
+ goto cleanup;
+ }
+ } else {
+ contents->dname_table = NULL;
+ }
+
+ contents->node_count = node_count;
+
+ /* Initialize NSEC3 params */
+ dbg_zone("Initializing NSEC3 parameters.\n");
+ contents->nsec3_params.algorithm = 0;
+ contents->nsec3_params.flags = 0;
+ contents->nsec3_params.iterations = 0;
+ contents->nsec3_params.salt_length = 0;
+ contents->nsec3_params.salt = NULL;
+
+ dbg_zone("Initializing zone trees.\n");
+ if (knot_zone_tree_init(contents->nodes) != KNOT_EOK
+ || knot_zone_tree_init(contents->nsec3_nodes) != KNOT_EOK) {
+ goto cleanup;
+ }
+
+ dbg_zone("Inserting apex into the zone tree.\n");
+ if (knot_zone_tree_insert(contents->nodes, apex) != KNOT_EOK) {
+ dbg_zone("Failed to insert apex to the zone tree.\n");
+ goto cleanup;
+ }
+
+#ifdef USE_HASH_TABLE
+ if (contents->node_count > 0) {
+ dbg_zone("Creating hash table.\n");
+ contents->table = ck_create_table(contents->node_count);
+ if (contents->table == NULL) {
+ goto cleanup;
+ }
+
+ // insert the apex into the hash table
+ dbg_zone("Inserting apex into the hash table.\n");
+ if (ck_insert_item(contents->table,
+ (const char *)knot_dname_name(
+ knot_node_owner(apex)),
+ knot_dname_size(knot_node_owner(apex)),
+ (void *)apex) != 0) {
+ ck_destroy_table(&contents->table, NULL, 0);
+ goto cleanup;
+ }
+ } else {
+ contents->table = NULL;
+ }
+#endif
+
+ // insert names from the apex to the domain table
+ if (use_domain_table) {
+ dbg_zone("Inserting names from apex to table.\n");
+ int rc = knot_zone_contents_dnames_from_node_to_table(
+ contents->dname_table, apex);
+ if (rc != KNOT_EOK) {
+ ck_destroy_table(&contents->table, NULL, 0);
+ goto cleanup;
+ }
+ }
+
+ return contents;
+
+cleanup:
+ dbg_zone("Cleaning up.\n");
+ free(contents->dname_table);
+ free(contents->nodes);
+ free(contents->nsec3_nodes);
+ free(contents);
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+//short knot_zone_contents_generation(const knot_zone_contents_t *zone)
+//{
+// return zone->generation;
+//}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_gen_is_old(const knot_zone_contents_t *contents)
+{
+ return (contents->generation == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_gen_is_new(const knot_zone_contents_t *contents)
+{
+ return (contents->generation == 1);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_gen_is_finished(const knot_zone_contents_t *contents)
+{
+ return (contents->generation == -1);
+}
+
+/*----------------------------------------------------------------------------*/
+
+//void knot_zone_contents_switch_generation(knot_zone_contents_t *zone)
+//{
+// zone->generation = 1 - zone->generation;
+//}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents)
+{
+ contents->generation = 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents)
+{
+ contents->generation = 1;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_contents_set_gen_new_finished(knot_zone_contents_t *contents)
+{
+ contents->generation = -1;
+}
+
+/*----------------------------------------------------------------------------*/
+
+uint16_t knot_zone_contents_class(const knot_zone_contents_t *contents)
+{
+ if (contents == NULL || contents->apex == NULL
+ || knot_node_rrset(contents->apex, KNOT_RRTYPE_SOA) == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return knot_rrset_class(knot_node_rrset(contents->apex,
+ KNOT_RRTYPE_SOA));
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_add_node(knot_zone_contents_t *zone,
+ knot_node_t *node, int create_parents,
+ uint8_t flags, int use_domain_table)
+{
+ if (zone == NULL || node == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ int ret = 0;
+ if ((ret = knot_zone_contents_check_node(zone, node)) != 0) {
+ return ret;
+ }
+
+ ret = knot_zone_tree_insert(zone->nodes, node);
+ if (ret != KNOT_EOK) {
+ dbg_zone("Failed to insert node into zone tree.\n");
+ return ret;
+ }
+
+#ifdef USE_HASH_TABLE
+ char *name = knot_dname_to_str(node->owner);
+// dbg_zone("Adding node with owner %s to hash table.\n", name);
+ free(name);
+ //assert(zone->table != NULL);
+ // add the node also to the hash table if authoritative, or deleg. point
+ if (zone->table != NULL
+ && ck_insert_item(zone->table,
+ (const char *)node->owner->name,
+ node->owner->size, (void *)node) != 0) {
+ dbg_zone("Error inserting node into hash table!\n");
+ /*! \todo Remove the node from the tree. */
+ return KNOT_EHASH;
+ }
+#endif
+ assert(knot_zone_contents_find_node(zone, node->owner));
+
+ if (use_domain_table) {
+ ret = knot_zone_contents_dnames_from_node_to_table(
+ zone->dname_table, node);
+ if (ret != KNOT_EOK) {
+ /*! \todo Remove node from the tree and hash table.*/
+ dbg_zone("Failed to add dnames into table.\n");
+ return ret;
+ }
+ }
+
+ knot_node_set_zone(node, zone->zone);
+
+ if (!create_parents) {
+ return KNOT_EOK;
+ }
+
+ dbg_zone("Creating parents of the node.\n");
+
+ knot_dname_t *chopped =
+ knot_dname_left_chop(knot_node_owner(node));
+ if (knot_dname_compare(knot_node_owner(zone->apex), chopped) == 0) {
+ dbg_zone("Zone apex is the parent.\n");
+ knot_node_set_parent(node, zone->apex);
+ } else {
+ knot_node_t *next_node;
+ while ((next_node
+ = knot_zone_contents_get_node(zone, chopped)) == NULL) {
+ /* Adding new dname to zone + add to table. */
+ dbg_zone("Creating new node.\n");
+ next_node = knot_node_new(chopped, NULL, flags);
+ if (next_node == NULL) {
+ /* Directly discard. */
+ knot_dname_free(&chopped);
+ return KNOT_ENOMEM;
+ }
+ if (use_domain_table) {
+ ret =
+ knot_zone_contents_dnames_from_node_to_table(
+ zone->dname_table, next_node);
+ if (ret != KNOT_EOK) {
+ /*! \todo Will next_node leak? */
+ knot_dname_release(chopped);
+ return ret;
+ }
+ }
+
+ if (next_node->owner != chopped) {
+ /* Node owner was in RDATA */
+ chopped = next_node->owner;
+ }
+
+ assert(knot_zone_contents_find_node(zone, chopped)
+ == NULL);
+ assert(knot_node_owner(next_node) == chopped);
+
+ dbg_zone("Inserting new node to zone tree.\n");
+// TREE_INSERT(zone->tree, knot_node, avl, next_node);
+
+ ret = knot_zone_tree_insert(zone->nodes,
+ next_node);
+ if (ret != KNOT_EOK) {
+ dbg_zone("Failed to insert new node "
+ "to zone tree.\n");
+ /*! \todo Delete the node?? */
+ /* Directly discard. */
+ knot_dname_release(chopped);
+ return ret;
+ }
+
+#ifdef USE_HASH_TABLE
+dbg_zone_exec(
+ char *name = knot_dname_to_str(
+ knot_node_owner(next_node));
+ dbg_zone("Adding new node with owner %s to "
+ "hash table.\n", name);
+ free(name);
+);
+
+ if (zone->table != NULL
+ && ck_insert_item(zone->table,
+ (const char *)knot_dname_name(
+ knot_node_owner(next_node)),
+ knot_dname_size(knot_node_owner(next_node)),
+ (void *)next_node) != 0) {
+ dbg_zone("Error inserting node into "
+ "hash table!\n");
+ /*! \todo Delete the node?? */
+ /* Directly discard. */
+ knot_dname_release(chopped);
+ return KNOT_EHASH;
+ }
+
+ // set parent
+ knot_node_set_parent(node, next_node);
+
+ // set zone
+ knot_node_set_zone(next_node, zone->zone);
+
+ // check if the node is not wildcard child of the parent
+ if (knot_dname_is_wildcard(
+ knot_node_owner(node))) {
+ knot_node_set_wildcard_child(next_node, node);
+ }
+#endif
+ dbg_zone("Next parent.\n");
+ node = next_node;
+ knot_dname_t *chopped_last = chopped;
+ chopped = knot_dname_left_chop(chopped);
+
+ /* Release last chop, reference is already stored
+ * in next_node.
+ */
+ knot_dname_release(chopped_last);
+
+ }
+ // set the found parent (in the zone) as the parent of the last
+ // inserted node
+ assert(knot_node_parent(node, 0) == NULL);
+ knot_node_set_parent(node, next_node);
+
+ dbg_zone("Created all parents.\n");
+ }
+
+ /* Directly discard. */
+ /*! \todo This may be double-release. */
+ knot_dname_release(chopped);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_add_rrset(knot_zone_contents_t *zone,
+ knot_rrset_t *rrset, knot_node_t **node,
+ knot_rrset_dupl_handling_t dupl,
+ int use_domain_table)
+{
+ if (zone == NULL || rrset == NULL || zone->apex == NULL
+ || zone->apex->owner == NULL || node == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // check if the RRSet belongs to the zone
+ if (knot_dname_compare(knot_rrset_owner(rrset),
+ zone->apex->owner) != 0
+ && !knot_dname_is_subdomain(knot_rrset_owner(rrset),
+ zone->apex->owner)) {
+ return KNOT_EBADZONE;
+ }
+
+ if ((*node) == NULL
+ && (*node = knot_zone_contents_get_node(zone,
+ knot_rrset_owner(rrset))) == NULL) {
+ return KNOT_ENONODE;
+ }
+
+ assert(*node != NULL);
+
+ // add all domain names from the RRSet to domain name table
+ int rc;
+
+ /*! \todo REMOVE RRSET */
+ rc = knot_node_add_rrset(*node, rrset,
+ dupl == KNOT_RRSET_DUPL_MERGE);
+ if (rc < 0) {
+ dbg_zone("Failed to add RRSet to node.\n");
+ return rc;
+ }
+
+ int ret = rc;
+
+ if (use_domain_table) {
+ dbg_zone("Saving RRSet to table.\n");
+ rc = knot_zone_contents_dnames_from_rrset_to_table(
+ zone->dname_table, rrset, 0, (*node)->owner);
+ if (rc != KNOT_EOK) {
+ dbg_zone("Error saving domain names from "
+ "RRSIGs to the domain name table.\n "
+ "The zone may be in an inconsistent "
+ "state.\n");
+ // WARNING: the zone is not in consistent state now -
+ // there may be domain names in it that are not inserted
+ // into the domain table
+ return rc;
+ }
+ }
+
+ // replace RRSet's owner with the node's owner (that is already in the
+ // table)
+ /*! \todo Do even if domain table is not used?? */
+ if (ret == KNOT_EOK && rrset->owner != (*node)->owner) {
+ knot_rrset_set_owner(rrset, (*node)->owner);
+ }
+
+ dbg_zone("RRSet OK.\n");
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_add_rrsigs(knot_zone_contents_t *zone,
+ knot_rrset_t *rrsigs,
+ knot_rrset_t **rrset,
+ knot_node_t **node,
+ knot_rrset_dupl_handling_t dupl,
+ int use_domain_table)
+{
+ if (zone == NULL || rrsigs == NULL || rrset == NULL || node == NULL
+ || zone->apex == NULL || zone->apex->owner == NULL) {
+dbg_zone_exec(
+ dbg_zone("Parameters: zone=%p, rrsigs=%p, rrset=%p, "
+ "node=%p\n", zone, rrsigs, rrset, node);
+ if (zone != NULL) {
+ dbg_zone("zone->apex=%p\n", zone->apex);
+ if (zone->apex != NULL) {
+ dbg_zone("zone->apex->owner=%p\n",
+ zone->apex->owner);
+ }
+ }
+);
+ return KNOT_EBADARG;
+ }
+
+ // check if the RRSet belongs to the zone
+ if (*rrset != NULL
+ && knot_dname_compare(knot_rrset_owner(*rrset),
+ zone->apex->owner) != 0
+ && !knot_dname_is_subdomain(knot_rrset_owner(*rrset),
+ zone->apex->owner)) {
+ return KNOT_EBADZONE;
+ }
+
+ // check if the RRSIGs belong to the RRSet
+ if (*rrset != NULL
+ && (knot_dname_compare(knot_rrset_owner(rrsigs),
+ knot_rrset_owner(*rrset)) != 0)) {
+ dbg_zone("RRSIGs does not belong to the given RRSet.\n");
+ return KNOT_EBADARG;
+ }
+
+ // if no RRSet given, try to find the right RRSet
+ if (*rrset == NULL) {
+ // even no node given
+ // find proper node
+ knot_node_t *(*get_node)(const knot_zone_contents_t *,
+ const knot_dname_t *)
+ = (knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(rrsigs)) == KNOT_RRTYPE_NSEC3)
+ ? knot_zone_contents_get_nsec3_node
+ : knot_zone_contents_get_node;
+
+ if (*node == NULL
+ && (*node = get_node(
+ zone, knot_rrset_owner(rrsigs))) == NULL) {
+ dbg_zone("Failed to find node for RRSIGs.\n");
+ return KNOT_ENONODE;
+ }
+
+ assert(*node != NULL);
+
+ // find the RRSet in the node
+ // take only the first RDATA from the RRSIGs
+ dbg_zone("Finding RRSet for type %s\n",
+ knot_rrtype_to_string(
+ knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(rrsigs))));
+ *rrset = knot_node_get_rrset(
+ *node, knot_rdata_rrsig_type_covered(
+ knot_rrset_rdata(rrsigs)));
+ if (*rrset == NULL) {
+ dbg_zone("Failed to find RRSet for RRSIGs.\n");
+ return KNOT_ENORRSET;
+ }
+ }
+
+ assert(*rrset != NULL);
+
+ // add all domain names from the RRSet to domain name table
+ int rc;
+ int ret = KNOT_EOK;
+
+ rc = knot_rrset_add_rrsigs(*rrset, rrsigs, dupl);
+ if (rc < 0) {
+ dbg_dname("Failed to add RRSIGs to RRSet.\n");
+ return rc;
+ } else if (rc > 0) {
+ assert(dupl == KNOT_RRSET_DUPL_MERGE);
+ ret = 1;
+ }
+
+ if (use_domain_table) {
+ dbg_zone("Saving RRSIG RRSet to table.\n");
+ rc = knot_zone_contents_dnames_from_rrset_to_table(
+ zone->dname_table, rrsigs, 0, (*rrset)->owner);
+ if (rc != KNOT_EOK) {
+ dbg_zone("Error saving domain names from "
+ "RRSIGs to the domain name table.\n "
+ "The zone may be in an inconsistent "
+ "state.\n");
+ // WARNING: the zone is not in consistent state now -
+ // there may be domain names in it that are not inserted
+ // into the domain table
+ return rc;
+ }
+ }
+
+ // replace RRSet's owner with the node's owner (that is already in the
+ // table)
+ if ((*rrset)->owner != (*rrset)->rrsigs->owner) {
+ knot_rrset_set_owner((*rrset)->rrsigs, (*rrset)->owner);
+ }
+
+ dbg_zone("RRSIGs OK\n");
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone,
+ knot_node_t *node, int create_parents,
+ uint8_t flags, int use_domain_table)
+{
+ UNUSED(create_parents);
+ UNUSED(flags);
+
+ if (zone == NULL || node == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ int ret = 0;
+ if ((ret = knot_zone_contents_check_node(zone, node)) != 0) {
+ return ret;
+ }
+
+ // how to know if this is successfull??
+// TREE_INSERT(zone->nsec3_nodes, knot_node, avl, node);
+ knot_zone_tree_insert(zone->nsec3_nodes, node);
+
+ if (use_domain_table) {
+ ret = knot_zone_contents_dnames_from_node_to_table(
+ zone->dname_table, node);
+ if (ret != KNOT_EOK) {
+ /*! \todo Remove the node from the tree. */
+ dbg_zone("Failed to add dnames into table.\n");
+ return ret;
+ }
+ }
+
+ // no parents to be created, the only parent is the zone apex
+ // set the apex as the parent of the node
+ knot_node_set_parent(node, zone->apex);
+
+ // set the zone to the node
+ knot_node_set_zone(node, zone->zone);
+
+ // cannot be wildcard child, so nothing to be done
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *zone,
+ knot_rrset_t *rrset,
+ knot_node_t **node,
+ knot_rrset_dupl_handling_t dupl,
+ int use_domain_table)
+{
+ if (zone == NULL || rrset == NULL || zone->apex == NULL
+ || zone->apex->owner == NULL || node == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // check if the RRSet belongs to the zone
+ if (knot_dname_compare(knot_rrset_owner(rrset),
+ zone->apex->owner) != 0
+ && !knot_dname_is_subdomain(knot_rrset_owner(rrset),
+ zone->apex->owner)) {
+ return KNOT_EBADZONE;
+ }
+
+ if ((*node) == NULL
+ && (*node = knot_zone_contents_get_nsec3_node(
+ zone, knot_rrset_owner(rrset))) == NULL) {
+ return KNOT_ENONODE;
+ }
+
+ assert(*node != NULL);
+
+ // add all domain names from the RRSet to domain name table
+ int rc;
+
+ /*! \todo REMOVE RRSET */
+ rc = knot_node_add_rrset(*node, rrset,
+ dupl == KNOT_RRSET_DUPL_MERGE);
+ if (rc < 0) {
+ return rc;
+ }
+
+ int ret = rc;
+
+ if (use_domain_table) {
+ dbg_zone("Saving NSEC3 RRSet to table.\n");
+ rc = knot_zone_contents_dnames_from_rrset_to_table(
+ zone->dname_table, rrset, 0, (*node)->owner);
+ if (rc != KNOT_EOK) {
+ dbg_zone("Error saving domain names from "
+ "RRSIGs to the domain name table.\n "
+ "The zone may be in an inconsistent "
+ "state.\n");
+ // WARNING: the zone is not in consistent state now -
+ // there may be domain names in it that are not inserted
+ // into the domain table
+ return rc;
+ }
+ }
+
+ // replace RRSet's owner with the node's owner (that is already in the
+ // table)
+ /*! \todo Do even if domain table is not used? */
+ if (rrset->owner != (*node)->owner) {
+ knot_rrset_set_owner(rrset, (*node)->owner);
+ }
+
+ dbg_zone("NSEC3 OK\n");
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_remove_node(knot_zone_contents_t *contents,
+ const knot_node_t *node, knot_zone_tree_node_t **removed_tree,
+ ck_hash_table_item_t **removed_hash)
+{
+ if (contents == NULL || node == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ const knot_dname_t *owner = knot_node_owner(node);
+
+ // 1) remove the node from hash table
+ *removed_hash = NULL;
+ *removed_hash = ck_remove_item(contents->table,
+ (const char *)knot_dname_name(owner),
+ knot_dname_size(owner));
+// int ret = ck_detete_item(contents->table,
+// (const char *)knot_dname_name(owner),
+// knot_dname_size(owner), NULL, 0);
+ if (*removed_hash == NULL) {
+ return KNOT_ENONODE;
+ }
+
+ // 2) remove the node from the zone tree
+ *removed_tree = NULL;
+ int ret = knot_zone_tree_remove(contents->nodes, owner, removed_tree);
+ if (ret != KNOT_EOK) {
+ return KNOT_ENONODE;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_remove_nsec3_node(knot_zone_contents_t *contents,
+ const knot_node_t *node, knot_zone_tree_node_t **removed)
+{
+ if (contents == NULL || node == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ const knot_dname_t *owner = knot_node_owner(node);
+
+ // remove the node from the zone tree
+ *removed = NULL;
+ int ret = knot_zone_tree_remove(contents->nsec3_nodes, owner, removed);
+ if (ret != KNOT_EOK) {
+ return KNOT_ENONODE;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_create_and_fill_hash_table(
+ knot_zone_contents_t *zone)
+{
+ if (zone == NULL || zone->apex == NULL || zone->apex->owner == NULL) {
+ return KNOT_EBADARG;
+ }
+ /*
+ * 1) Create hash table.
+ */
+#ifdef USE_HASH_TABLE
+ if (zone->node_count > 0) {
+ zone->table = ck_create_table(zone->node_count);
+ if (zone->table == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // insert the apex into the hash table
+ if (ck_insert_item(zone->table,
+ (const char *)zone->apex->owner->name,
+ zone->apex->owner->size,
+ (void *)zone->apex) != 0) {
+ return KNOT_EHASH;
+ }
+ } else {
+ zone->table = NULL;
+ return KNOT_EOK; // OK?
+ }
+
+ /*
+ * 2) Fill in the hash table.
+ *
+ * In this point, the nodes in the zone must be adjusted, so that only
+ * relevant nodes (authoritative and delegation points are inserted.
+ *
+ * TODO: how to know if this was successful??
+ */
+ /*! \todo Replace by zone tree. */
+ int ret = knot_zone_tree_forward_apply_inorder(zone->nodes,
+ knot_zone_contents_node_to_hash, zone);
+ if (ret != KNOT_EOK) {
+ dbg_zone("Failed to insert nodes to hash table.\n");
+ return ret;
+ }
+
+#endif
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_zone_contents_get_node(const knot_zone_contents_t *zone,
+ const knot_dname_t *name)
+{
+ if (zone == NULL || name == NULL) {
+ return NULL;
+ }
+
+ // create dummy node to use for lookup
+// knot_node_t *tmp = knot_node_new((knot_dname_t *)name, NULL);
+// knot_node_t *n = TREE_FIND(zone->tree, knot_node, avl, tmp);
+// knot_node_free(&tmp, 0);
+
+ knot_node_t *n;
+ int ret = knot_zone_tree_get(zone->nodes, name, &n);
+ if (ret != KNOT_EOK) {
+ dbg_zone("Failed to find name in the zone tree.\n");
+ return NULL;
+ }
+
+ return n;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_zone_contents_get_nsec3_node(
+ const knot_zone_contents_t *zone, const knot_dname_t *name)
+{
+ if (zone == NULL || name == NULL) {
+ return NULL;
+ }
+
+ // create dummy node to use for lookup
+// knot_node_t *tmp = knot_node_new((knot_dname_t *)name, NULL);
+// knot_node_t *n = TREE_FIND(zone->nsec3_nodes, knot_node, avl, tmp);
+// knot_node_free(&tmp, 0);
+ knot_node_t *n;
+ int ret = knot_zone_tree_get(zone->nsec3_nodes, name, &n);
+
+ if (ret != KNOT_EOK) {
+ dbg_zone("Failed to find NSEC3 name in the zone tree."
+ "\n");
+ return NULL;
+ }
+
+ return n;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_zone_contents_find_node(
+ const knot_zone_contents_t *zone,const knot_dname_t *name)
+{
+ return knot_zone_contents_get_node(zone, name);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_find_dname(const knot_zone_contents_t *zone,
+ const knot_dname_t *name,
+ const knot_node_t **node,
+ const knot_node_t **closest_encloser,
+ const knot_node_t **previous)
+{
+ if (zone == NULL || name == NULL || node == NULL
+ || closest_encloser == NULL || previous == NULL
+ || zone->apex == NULL || zone->apex->owner == NULL) {
+ return KNOT_EBADARG;
+ }
+
+dbg_zone_exec(
+ char *name_str = knot_dname_to_str(name);
+ char *zone_str = knot_dname_to_str(zone->apex->owner);
+ dbg_zone("Searching for name %s in zone %s...\n",
+ name_str, zone_str);
+ free(name_str);
+ free(zone_str);
+);
+
+ if (knot_dname_compare(name, zone->apex->owner) == 0) {
+ *node = zone->apex;
+ *closest_encloser = *node;
+ return KNOT_ZONE_NAME_FOUND;
+ }
+
+ if (!knot_dname_is_subdomain(name, zone->apex->owner)) {
+ *node = NULL;
+ *closest_encloser = NULL;
+ return KNOT_EBADZONE;
+ }
+
+ knot_node_t *found = NULL, *prev = NULL;
+
+ int exact_match = knot_zone_contents_find_in_tree(zone->nodes, name,
+ &found, &prev);
+ assert(exact_match >= 0);
+ *node = found;
+ *previous = prev;
+
+dbg_zone_exec(
+ char *name_str = (*node) ? knot_dname_to_str((*node)->owner)
+ : "(nil)";
+ char *name_str2 = (*previous != NULL)
+ ? knot_dname_to_str((*previous)->owner)
+ : "(nil)";
+ dbg_zone("Search function returned %d, node %s and prev: %s\n",
+ exact_match, name_str, name_str2);
+
+ if (*node) {
+ free(name_str);
+ }
+ if (*previous != NULL) {
+ free(name_str2);
+ }
+);
+
+ *closest_encloser = *node;
+
+ // there must be at least one node with domain name less or equal to
+ // the searched name if the name belongs to the zone (the root)
+ if (*node == NULL) {
+ return KNOT_EBADZONE;
+ }
+
+ // TODO: this could be replaced by saving pointer to closest encloser
+ // in node
+
+ if (!exact_match) {
+ int matched_labels = knot_dname_matched_labels(
+ knot_node_owner((*closest_encloser)), name);
+ while (matched_labels < knot_dname_label_count(
+ knot_node_owner((*closest_encloser)))) {
+ (*closest_encloser) =
+ knot_node_parent((*closest_encloser), 1);
+ assert(*closest_encloser);
+ }
+ }
+dbg_zone_exec(
+ char *n = knot_dname_to_str(knot_node_owner((*closest_encloser)));
+ dbg_zone("Closest encloser: %s\n", n);
+ free(n);
+);
+
+ dbg_zone("find_dname() returning %d\n", exact_match);
+
+ return (exact_match)
+ ? KNOT_ZONE_NAME_FOUND
+ : KNOT_ZONE_NAME_NOT_FOUND;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_zone_contents_get_previous(
+ const knot_zone_contents_t *zone, const knot_dname_t *name)
+{
+ if (zone == NULL || name == NULL) {
+ return NULL;
+ }
+
+ knot_node_t *found = NULL, *prev = NULL;
+
+ int exact_match = knot_zone_contents_find_in_tree(zone->nodes, name,
+ &found, &prev);
+ assert(exact_match >= 0);
+ assert(prev != NULL);
+
+ return prev;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_zone_contents_find_previous(
+ const knot_zone_contents_t *zone, const knot_dname_t *name)
+{
+ return knot_zone_contents_get_previous(zone, name);
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_zone_contents_get_previous_nsec3(
+ const knot_zone_contents_t *zone, const knot_dname_t *name)
+{
+ if (zone == NULL || name == NULL) {
+ return NULL;
+ }
+
+ knot_node_t *found = NULL, *prev = NULL;
+
+ int exact_match = knot_zone_contents_find_in_tree(zone->nsec3_nodes,
+ name, &found, &prev);
+ assert(exact_match >= 0);
+ assert(prev != NULL);
+
+ return prev;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_zone_contents_find_previous_nsec3(
+ const knot_zone_contents_t *zone, const knot_dname_t *name)
+{
+ return knot_zone_contents_get_previous(zone, name);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void knot_zone_contents_left_chop(char *name, size_t *size)
+{
+ short label_size = name[0];
+
+ memmove(name, name + label_size + 1, *size -label_size - 1);
+ *size = *size - label_size - 1;
+}
+
+/*----------------------------------------------------------------------------*/
+#ifdef USE_HASH_TABLE
+int knot_zone_contents_find_dname_hash(const knot_zone_contents_t *zone,
+ const knot_dname_t *name,
+ const knot_node_t **node,
+ const knot_node_t **closest_encloser)
+{
+ if (zone == NULL || name == NULL || node == NULL
+ || closest_encloser == NULL) {
+ return KNOT_EBADARG;
+ }
+
+dbg_zone_exec(
+ char *name_str = knot_dname_to_str(name);
+ char *zone_str = knot_dname_to_str(zone->apex->owner);
+ dbg_zone("Searching for name %s in zone %s...\n",
+ name_str, zone_str);
+ free(name_str);
+ free(zone_str);
+);
+
+ if (knot_dname_compare(name, zone->apex->owner) == 0) {
+ *node = zone->apex;
+ *closest_encloser = *node;
+ return KNOT_ZONE_NAME_FOUND;
+ }
+
+ if (!knot_dname_is_subdomain(name, zone->apex->owner)) {
+ *node = NULL;
+ *closest_encloser = NULL;
+ return KNOT_EBADZONE;
+ }
+
+ // temporary name used for hashing
+ char name_tmp[KNOT_MAX_DNAME_LENGTH];
+ size_t name_size = name->size;
+ if (knot_dname_to_lower_copy(name, name_tmp, KNOT_MAX_DNAME_LENGTH)
+ != KNOT_EOK) {
+ return KNOT_ERROR;
+ }
+
+ const ck_hash_table_item_t *item = ck_find_item(zone->table,
+ name_tmp, name_size);
+
+ if (item != NULL) {
+ *node = (const knot_node_t *)item->value;
+ *closest_encloser = *node;
+
+ dbg_zone("Found node in hash table: %p (owner %p, "
+ "labels: %d)\n", *node, (*node)->owner,
+ knot_dname_label_count((*node)->owner));
+ assert(*node != NULL);
+ assert(*closest_encloser != NULL);
+ return KNOT_ZONE_NAME_FOUND;
+ }
+
+ *node = NULL;
+
+ // chop leftmost labels until some node is found
+ // copy the name for chopping
+ /* Local allocation, will be discarded. */
+ //knot_dname_t *name_copy = knot_dname_deep_copy(name);
+dbg_zone_exec(
+ //char *n = knot_dname_to_str(name_copy);
+ dbg_zone("Finding closest encloser..\nStarting with: %.*s\n",
+ (int)name_size, name_tmp);
+ //free(n);
+);
+
+ while (item == NULL) {
+ //knot_dname_left_chop_no_copy(name_copy);
+ knot_zone_contents_left_chop(name_tmp, &name_size);
+dbg_zone_exec(
+ //char *n = knot_dname_to_str(name_copy);
+ dbg_zone("Chopped leftmost label: %.*s\n",
+ (int)name_size, name_tmp);
+ //free(n);
+);
+ // not satisfied in root zone!!
+ //assert(name_copy->label_count > 0);
+ assert(name_size > 0);
+
+ item = ck_find_item(zone->table, name_tmp, name_size);
+ }
+
+ /* Directly discard. */
+ //knot_dname_free(&name_copy);
+
+ assert(item != NULL);
+ *closest_encloser = (const knot_node_t *)item->value;
+
+ return KNOT_ZONE_NAME_NOT_FOUND;
+}
+#endif
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_zone_contents_find_nsec3_node(
+ const knot_zone_contents_t *zone, const knot_dname_t *name)
+{
+ return knot_zone_contents_get_nsec3_node(zone, name);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_find_nsec3_for_name(const knot_zone_contents_t *zone,
+ const knot_dname_t *name,
+ const knot_node_t **nsec3_node,
+ const knot_node_t **nsec3_previous,
+ int check_ver)
+{
+ if (zone == NULL || name == NULL
+ || nsec3_node == NULL || nsec3_previous == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_dname_t *nsec3_name = NULL;
+ int ret = knot_zone_contents_nsec3_name(zone, name, &nsec3_name);
+
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+dbg_zone_exec(
+ char *n = knot_dname_to_str(nsec3_name);
+ dbg_zone("NSEC3 node name: %s.\n", n);
+ free(n);
+);
+
+ const knot_node_t *found = NULL, *prev = NULL;
+
+ // create dummy node to use for lookup
+ int exact_match = knot_zone_tree_find_less_or_equal(
+ zone->nsec3_nodes, nsec3_name, &found, &prev, check_ver);
+ assert(exact_match >= 0);
+
+ knot_dname_release(nsec3_name);
+
+dbg_zone_exec(
+ if (found) {
+ char *n = knot_dname_to_str(found->owner);
+ dbg_zone("Found NSEC3 node: %s.\n", n);
+ free(n);
+ } else {
+ dbg_zone("Found no NSEC3 node.\n");
+ }
+
+ if (prev) {
+ assert(prev->owner);
+ char *n = knot_dname_to_str(prev->owner);
+ dbg_zone("Found previous NSEC3 node: %s.\n", n);
+ free(n);
+ } else {
+ dbg_zone("Found no previous NSEC3 node.\n");
+ }
+);
+ *nsec3_node = found;
+
+ if (prev == NULL) {
+ // either the returned node is the root of the tree, or it is
+ // the leftmost node in the tree; in both cases node was found
+ // set the previous node of the found node
+ assert(exact_match);
+ assert(*nsec3_node != NULL);
+ *nsec3_previous = knot_node_previous(*nsec3_node, check_ver);
+ } else {
+ *nsec3_previous = prev;
+ }
+
+ dbg_zone("find_nsec3_for_name() returning %d\n", exact_match);
+
+ return (exact_match)
+ ? KNOT_ZONE_NAME_FOUND
+ : KNOT_ZONE_NAME_NOT_FOUND;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_node_t *knot_zone_contents_apex(
+ const knot_zone_contents_t *zone)
+{
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ return zone->apex;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_node_t *knot_zone_contents_get_apex(const knot_zone_contents_t *zone)
+{
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ return zone->apex;
+}
+
+/*----------------------------------------------------------------------------*/
+
+//knot_dname_t *knot_zone_contents_name(const knot_zone_contents_t *zone)
+//{
+// if (zone == NULL) {
+// return NULL;
+// }
+
+// return zone->name;
+//}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_adjust(knot_zone_contents_t *zone, int check_ver)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // load NSEC3PARAM (needed on adjusting function)
+ knot_zone_contents_load_nsec3param(zone);
+
+ knot_zone_adjust_arg_t adjust_arg;
+ adjust_arg.zone = zone;
+ adjust_arg.first_node = NULL;
+ adjust_arg.previous_node = NULL;
+ adjust_arg.check_ver = check_ver;
+
+ dbg_zone("Adjusting normal nodes.\n");
+ int ret = knot_zone_tree_forward_apply_inorder(zone->nodes,
+ knot_zone_contents_adjust_node_in_tree,
+ &adjust_arg);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ dbg_zone("Done.\n");
+
+ assert(zone->apex == adjust_arg.first_node);
+ knot_node_set_previous(zone->apex, adjust_arg.previous_node);
+
+ adjust_arg.first_node = NULL;
+ adjust_arg.previous_node = NULL;
+
+ dbg_zone("Adjusting NSEC3 nodes.\n");
+ ret = knot_zone_tree_forward_apply_inorder(
+ zone->nsec3_nodes,
+ knot_zone_contents_adjust_nsec3_node_in_tree,
+ &adjust_arg);
+
+ dbg_zone("Done.\n");
+ if (adjust_arg.first_node) {
+ knot_node_set_previous(adjust_arg.first_node,
+ adjust_arg.previous_node);
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_load_nsec3param(knot_zone_contents_t *zone)
+{
+ if (zone == NULL || zone->apex == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ const knot_rrset_t *rrset = knot_node_rrset(zone->apex,
+ KNOT_RRTYPE_NSEC3PARAM);
+
+ if (rrset != NULL) {
+ knot_nsec3_params_from_wire(&zone->nsec3_params, rrset);
+ } else {
+ memset(&zone->nsec3_params, 0, sizeof(knot_nsec3_params_t));
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_nsec3_enabled(const knot_zone_contents_t *zone)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ //return (zone->nsec3_params.algorithm != 0);
+ return (zone->nsec3_nodes->th_root != NULL);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_nsec3_params_t *knot_zone_contents_nsec3params(
+ const knot_zone_contents_t *zone)
+{
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ if (knot_zone_contents_nsec3_enabled(zone)) {
+ return &zone->nsec3_params;
+ } else {
+ return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_tree_apply_postorder(knot_zone_contents_t *zone,
+ void (*function)(knot_node_t *node, void *data),
+ void *data)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_tree_func_t f;
+ f.func = function;
+ f.data = data;
+
+ return knot_zone_tree_forward_apply_postorder(zone->nodes,
+ knot_zone_tree_apply, &f);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_tree_apply_inorder(knot_zone_contents_t *zone,
+ void (*function)(knot_node_t *node, void *data),
+ void *data)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_tree_func_t f;
+ f.func = function;
+ f.data = data;
+
+ return knot_zone_tree_forward_apply_inorder(zone->nodes,
+ knot_zone_tree_apply, &f);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_tree_apply_inorder_reverse(
+ knot_zone_contents_t *zone,
+ void (*function)(knot_node_t *node, void *data), void *data)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_tree_func_t f;
+ f.func = function;
+ f.data = data;
+
+ return knot_zone_tree_reverse_apply_inorder(zone->nodes,
+ knot_zone_tree_apply, &f);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_nsec3_apply_postorder(knot_zone_contents_t *zone,
+ void (*function)(knot_node_t *node, void *data),
+ void *data)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_tree_func_t f;
+ f.func = function;
+ f.data = data;
+
+ return knot_zone_tree_forward_apply_postorder(
+ zone->nsec3_nodes, knot_zone_tree_apply, &f);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_nsec3_apply_inorder(knot_zone_contents_t *zone,
+ void (*function)(knot_node_t *node, void *data),
+ void *data)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_tree_func_t f;
+ f.func = function;
+ f.data = data;
+
+ return knot_zone_tree_forward_apply_inorder(
+ zone->nsec3_nodes, knot_zone_tree_apply, &f);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_nsec3_apply_inorder_reverse(
+ knot_zone_contents_t *zone,
+ void (*function)(knot_node_t *node, void *data), void *data)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_tree_func_t f;
+ f.func = function;
+ f.data = data;
+
+ return knot_zone_tree_reverse_apply_inorder(
+ zone->nsec3_nodes, knot_zone_tree_apply, &f);
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_tree_t *knot_zone_contents_get_nodes(
+ knot_zone_contents_t *contents)
+{
+ return contents->nodes;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_tree_t *knot_zone_contents_get_nsec3_nodes(
+ knot_zone_contents_t *contents)
+{
+ return contents->nsec3_nodes;
+}
+
+/*----------------------------------------------------------------------------*/
+
+ck_hash_table_t *knot_zone_contents_get_hash_table(
+ knot_zone_contents_t *contents)
+{
+ return contents->table;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_dname_table_apply(knot_zone_contents_t *contents,
+ void (*function)(knot_dname_t *,
+ void *),
+ void *data)
+{
+ if (contents == NULL || function == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_dname_table_tree_inorder_apply(contents->dname_table,
+ function, data);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from,
+ knot_zone_contents_t **to)
+{
+ if (from == NULL || to == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ /* Copy to same destination as source. */
+ if (from == *to) {
+ return KNOT_EBADARG;
+ }
+
+ int ret = KNOT_EOK;
+
+ knot_zone_contents_t *contents = (knot_zone_contents_t *)calloc(
+ 1, sizeof(knot_zone_contents_t));
+ if (contents == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOT_ENOMEM;
+ }
+
+ contents->apex = from->apex;
+
+ contents->nodes = malloc(sizeof(knot_zone_tree_t));
+ if (contents->nodes == NULL) {
+ ERR_ALLOC_FAILED;
+ ret = KNOT_ENOMEM;
+ goto cleanup;
+ }
+
+ contents->nsec3_nodes = malloc(sizeof(knot_zone_tree_t));
+ if (contents->nsec3_nodes == NULL) {
+ ERR_ALLOC_FAILED;
+ ret = KNOT_ENOMEM;
+ goto cleanup;
+ }
+
+ if (from->dname_table != NULL) {
+ contents->dname_table = knot_dname_table_new();
+ if (contents->dname_table == NULL) {
+ ERR_ALLOC_FAILED;
+ ret = KNOT_ENOMEM;
+ goto cleanup;
+ }
+ if ((ret = knot_dname_table_shallow_copy(from->dname_table,
+ contents->dname_table)) != KNOT_EOK) {
+ goto cleanup;
+ }
+ } else {
+ contents->dname_table = NULL;
+ }
+
+ contents->node_count = from->node_count;
+ contents->generation = from->generation;
+
+ contents->zone = from->zone;
+
+ /* Initialize NSEC3 params */
+ memcpy(&contents->nsec3_params, &from->nsec3_params,
+ sizeof(knot_nsec3_params_t));
+
+ if ((ret = knot_zone_tree_shallow_copy(from->nodes,
+ contents->nodes)) != KNOT_EOK
+ || (ret = knot_zone_tree_shallow_copy(from->nsec3_nodes,
+ contents->nsec3_nodes)) != KNOT_EOK) {
+ goto cleanup;
+ }
+
+#ifdef USE_HASH_TABLE
+ if (from->table != NULL) {
+// ret = ck_copy_table(from->table, &contents->table);
+ ret = ck_shallow_copy(from->table, &contents->table);
+ if (ret != 0) {
+ dbg_zone("knot_zone_contents_shallow_copy: "
+ "hash table copied\n");
+ ret = KNOT_ERROR;
+ goto cleanup;
+ }
+ }
+#endif
+
+ dbg_zone("knot_zone_contents_shallow_copy: "
+ "finished OK\n");
+
+ *to = contents;
+ return KNOT_EOK;
+
+cleanup:
+ knot_zone_tree_free(&contents->nodes);
+ knot_zone_tree_free(&contents->nsec3_nodes);
+ free(contents->dname_table);
+ free(contents);
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_contents_free(knot_zone_contents_t **contents)
+{
+ if (contents == NULL || *contents == NULL) {
+ return;
+ }
+
+ // free the zone tree, but only the structure
+ knot_zone_tree_free(&(*contents)->nodes);
+ knot_zone_tree_free(&(*contents)->nsec3_nodes);
+
+#ifdef USE_HASH_TABLE
+ if ((*contents)->table != NULL) {
+ ck_destroy_table(&(*contents)->table, NULL, 0);
+ }
+#endif
+ knot_nsec3_params_free(&(*contents)->nsec3_params);
+
+ knot_dname_table_free(&(*contents)->dname_table);
+
+ free(*contents);
+ *contents = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_contents_deep_free(knot_zone_contents_t **contents,
+ int destroy_dname_table)
+{
+ if (contents == NULL || *contents == NULL) {
+ return;
+ }
+
+ if ((*contents) != NULL) {
+
+#ifdef USE_HASH_TABLE
+ if ((*contents)->table != NULL) {
+ ck_destroy_table(&(*contents)->table, NULL, 0);
+ }
+#endif
+ /* has to go through zone twice, rdata may contain references to
+ node owners earlier in the zone which may be already freed */
+ /* NSEC3 tree is deleted first as it may contain references to
+ the normal tree. */
+
+ knot_zone_tree_reverse_apply_postorder(
+ (*contents)->nsec3_nodes,
+ knot_zone_contents_destroy_node_rrsets_from_tree,
+ (void*)1);
+
+ knot_zone_tree_reverse_apply_postorder(
+ (*contents)->nsec3_nodes,
+ knot_zone_contents_destroy_node_owner_from_tree, 0);
+
+ knot_zone_tree_reverse_apply_postorder(
+ (*contents)->nodes,
+ knot_zone_contents_destroy_node_rrsets_from_tree,
+ (void*)1);
+
+ knot_zone_tree_reverse_apply_postorder(
+ (*contents)->nodes,
+ knot_zone_contents_destroy_node_owner_from_tree, 0);
+
+ // free the zone tree, but only the structure
+ // (nodes are already destroyed)
+ dbg_zone("Destroying zone tree.\n");
+ knot_zone_tree_free(&(*contents)->nodes);
+ dbg_zone("Destroying NSEC3 zone tree.\n");
+ knot_zone_tree_free(&(*contents)->nsec3_nodes);
+
+ knot_nsec3_params_free(&(*contents)->nsec3_params);
+
+ if (destroy_dname_table) {
+ /*
+ * Hack, used in zcompile - destroys the table using
+ * dname_free() instead of dname_retain().
+ */
+ knot_dname_table_destroy(&(*contents)->dname_table);
+ } else {
+ knot_dname_table_deep_free(&(*contents)->dname_table);
+ }
+ }
+
+ free((*contents));
+ *contents = NULL;
+}
+
diff --git a/src/libknot/zone/zone-contents.h b/src/libknot/zone/zone-contents.h
new file mode 100644
index 0000000..2856f76
--- /dev/null
+++ b/src/libknot/zone/zone-contents.h
@@ -0,0 +1,556 @@
+/*!
+ * \file zone-contents.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Zone contents structure and API for manipulating it.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_ZONE_CONTENTS_H_
+#define _KNOT_ZONE_CONTENTS_H_
+
+//#include <time.h>
+
+#include "zone/node.h"
+#include "dname.h"
+#include "nsec3.h"
+#include "zone/dname-table.h"
+#include "common/tree.h"
+#include "hash/cuckoo-hash-table.h"
+
+#include "zone-tree.h"
+
+struct knot_zone;
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct knot_zone_contents_t {
+ knot_node_t *apex; /*!< Apex node of the zone (holding SOA) */
+
+ ck_hash_table_t *table; /*!< Hash table for holding zone nodes. */
+ knot_zone_tree_t *nodes;
+ knot_zone_tree_t *nsec3_nodes;
+
+ /*!
+ * \todo Unify the use of this field - authoritative nodes vs. all.
+ */
+ uint node_count;
+
+ knot_dname_table_t *dname_table;
+
+ knot_nsec3_params_t nsec3_params;
+
+ /*! \brief Generation of the zone during update.
+ *
+ * Possible values:
+ * - 0 - Original version of the zone. Old nodes should be used.
+ * - 1 - New (updated) zone. New nodes should be used.
+ * - -1 - New (updated) zone, but exactly the stored nodes should be
+ * used, no matter their generation.
+ */
+ short generation;
+
+ struct knot_zone *zone;
+} knot_zone_contents_t;
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex,
+ uint node_count,
+ int use_domain_table,
+ struct knot_zone *zone);
+
+time_t knot_zone_contents_version(const knot_zone_contents_t *contents);
+
+void knot_zone_contents_set_version(knot_zone_contents_t *contents,
+ time_t version);
+
+//short knot_zone_contents_generation(const knot_zone_contents_t *contents);
+
+int knot_zone_contents_gen_is_old(const knot_zone_contents_t *contents);
+int knot_zone_contents_gen_is_new(const knot_zone_contents_t *contents);
+int knot_zone_contents_gen_is_finished(const knot_zone_contents_t *contents);
+
+//void knot_zone_contents_switch_generation(knot_zone_contents_t *contents);
+
+void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents);
+void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents);
+void knot_zone_contents_set_gen_new_finished(knot_zone_contents_t *contents);
+
+uint16_t knot_zone_contents_class(const knot_zone_contents_t *contents);
+
+/*!
+ * \brief Adds a node to the given zone.
+ *
+ * Checks if the node belongs to the zone, i.e. if its owner is a subdomain of
+ * the zone's apex. It thus also forbids adding node with the same name as the
+ * zone apex.
+ *
+ * \warning This function may destroy domain names saved in the node, that
+ * are already present in the zone.
+ *
+ * \param zone Zone to add the node into.
+ * \param node Node to add into the zone.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_EBADZONE
+ * \retval KNOT_EHASH
+ */
+int knot_zone_contents_add_node(knot_zone_contents_t *contents,
+ knot_node_t *node, int create_parents,
+ uint8_t flags, int use_domain_table);
+
+/*!
+ * \brief Adds a RRSet to the given zone.
+ *
+ * Checks if the RRSet belongs to the zone, i.e. if its owner is a subdomain of
+ * the zone's apex. The RRSet is inserted only if the node is given, or if
+ * a node where the RRSet should belong is found in the zone.
+ *
+ * \warning The function does not check if the node is already inserted in the
+ * zone, just assumes that it is.
+ * \warning This function may destroy domain names saved in the RRSet, that
+ * are already present in the zone.
+ *
+ * \param zone Zone to add the node into.
+ * \param rrset RRSet to add into the zone.
+ * \param node Node the RRSet should be inserted into. (Should be a node of the
+ * given zone.) If set to NULL, the function will find proper node
+ * and set it to this parameter.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_EBADZONE
+ */
+int knot_zone_contents_add_rrset(knot_zone_contents_t *contents,
+ knot_rrset_t *rrset,
+ knot_node_t **node,
+ knot_rrset_dupl_handling_t dupl,
+ int use_domain_table);
+
+int knot_zone_contents_add_rrsigs(knot_zone_contents_t *contents,
+ knot_rrset_t *rrsigs,
+ knot_rrset_t **rrset, knot_node_t **node,
+ knot_rrset_dupl_handling_t dupl,
+ int use_domain_table);
+
+/*!
+ * \brief Adds a node holding NSEC3 records to the given zone.
+ *
+ * Checks if the node belongs to the zone, i.e. if its owner is a subdomain of
+ * the zone's apex. It does not check if the node really contains any NSEC3
+ * records, nor if the name is a hash (as there is actually no way of
+ * determining this).
+ *
+ * \param zone Zone to add the node into.
+ * \param node Node to add into the zone.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_EBADZONE
+ */
+int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *contents,
+ knot_node_t *node, int create_parents,
+ uint8_t flags, int use_domain_table);
+
+int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *contents,
+ knot_rrset_t *rrset,
+ knot_node_t **node,
+ knot_rrset_dupl_handling_t dupl,
+ int use_domain_table);
+
+int knot_zone_contents_remove_node(knot_zone_contents_t *contents,
+ const knot_node_t *node, knot_zone_tree_node_t **removed_tree,
+ ck_hash_table_item_t **removed_hash);
+
+//knot_zone_tree_node_t *knot_zone_contents_remove_node(
+// knot_zone_contents_t *contents, const knot_node_t *node);
+
+int knot_zone_contents_remove_nsec3_node(knot_zone_contents_t *contents,
+ const knot_node_t *node, knot_zone_tree_node_t **removed);
+
+/*!
+ * \warning Always call knot_zone_adjust_dnames() prior to calling this
+ * function. Otherwise the node count would not be set.
+ *
+ * \note Currently, all nodes (even non-authoritative) are inserted into the
+ * hash table.
+ */
+int knot_zone_contents_create_and_fill_hash_table(
+ knot_zone_contents_t *contents);
+
+/*!
+ * \brief Tries to find a node with the specified name in the zone.
+ *
+ * \param zone Zone where the name should be searched for.
+ * \param name Name to find.
+ *
+ * \return Corresponding node if found, NULL otherwise.
+ */
+knot_node_t *knot_zone_contents_get_node(
+ const knot_zone_contents_t *contents, const knot_dname_t *name);
+
+/*!
+ * \brief Tries to find a node with the specified name among the NSEC3 nodes
+ * of the zone.
+ *
+ * \param zone Zone where the name should be searched for.
+ * \param name Name to find.
+ *
+ * \return Corresponding node if found, NULL otherwise.
+ */
+knot_node_t *knot_zone_contents_get_nsec3_node(
+ const knot_zone_contents_t *contents, const knot_dname_t *name);
+
+/*!
+ * \brief Tries to find a node with the specified name in the zone.
+ *
+ * \note This function is identical to knot_zone_contents_get_node(), only it returns
+ * constant reference.
+ *
+ * \param zone Zone where the name should be searched for.
+ * \param name Name to find.
+ *
+ * \return Corresponding node if found, NULL otherwise.
+ */
+const knot_node_t *knot_zone_contents_find_node(
+ const knot_zone_contents_t *contents, const knot_dname_t *name);
+
+/*!
+ * \brief Tries to find domain name in the given zone using AVL tree.
+ *
+ * \param[in] zone Zone to search for the name.
+ * \param[in] name Domain name to search for.
+ * \param[out] node The found node (if it was found, otherwise it may contain
+ * arbitrary node).
+ * \param[out] closest_encloser Closest encloser of the given name in the zone.
+ * \param[out] previous Previous domain name in canonical order.
+ *
+ * \retval KNOT_ZONE_NAME_FOUND if node with owner \a name was found.
+ * \retval KNOT_ZONE_NAME_NOT_FOUND if it was not found.
+ * \retval KNOT_EBADARG
+ * \retval KNOT_EBADZONE
+ */
+int knot_zone_contents_find_dname(const knot_zone_contents_t *contents,
+ const knot_dname_t *name,
+ const knot_node_t **node,
+ const knot_node_t **closest_encloser,
+ const knot_node_t **previous);
+
+/*!
+ * \brief Finds previous name in canonical order to the given name in the zone.
+ *
+ * \param zone Zone to search for the name.
+ * \param name Domain name to find the previous domain name of.
+ *
+ * \return Previous node in canonical order, or NULL if some parameter is wrong.
+ */
+const knot_node_t *knot_zone_contents_find_previous(
+ const knot_zone_contents_t *contents, const knot_dname_t *name);
+
+knot_node_t *knot_zone_contents_get_previous(
+ const knot_zone_contents_t *contents, const knot_dname_t *name);
+
+const knot_node_t *knot_zone_contents_find_previous_nsec3(
+ const knot_zone_contents_t *contents, const knot_dname_t *name);
+
+knot_node_t *knot_zone_contents_get_previous_nsec3(
+ const knot_zone_contents_t *contents, const knot_dname_t *name);
+
+#ifdef USE_HASH_TABLE
+/*!
+ * \brief Tries to find domain name in the given zone using the hash table.
+ *
+ * \param[in] zone Zone to search for the name.
+ * \param[in] name Domain name to search for.
+ * \param[out] node The found node (if it was found, otherwise it may contain
+ * arbitrary node).
+ * \param[out] closest_encloser Closest encloser of the given name in the zone.
+ * \param[out] previous Previous domain name in canonical order.
+ *
+ * \retval KNOT_ZONE_NAME_FOUND if node with owner \a name was found.
+ * \retval KNOT_ZONE_NAME_NOT_FOUND if it was not found.
+ * \retval KNOT_EBADARG
+ * \retval KNOT_EBADZONE
+ */
+int knot_zone_contents_find_dname_hash(const knot_zone_contents_t *contents,
+ const knot_dname_t *name,
+ const knot_node_t **node,
+ const knot_node_t **closest_encloser);
+#endif
+
+/*!
+ * \brief Tries to find a node with the specified name among the NSEC3 nodes
+ * of the zone.
+ *
+ * \note This function is identical to knot_zone_contents_get_nsec3_node(), only it
+ * returns constant reference.
+ *
+ * \param zone Zone where the name should be searched for.
+ * \param name Name to find.
+ *
+ * \return Corresponding node if found, NULL otherwise.
+ */
+const knot_node_t *knot_zone_contents_find_nsec3_node(
+ const knot_zone_contents_t *contents, const knot_dname_t *name);
+
+/*!
+ * \brief Finds NSEC3 node and previous NSEC3 node in canonical order,
+ * corresponding to the given domain name.
+ *
+ * This functions creates a NSEC3 hash of \a name and tries to find NSEC3 node
+ * with the hashed domain name as owner.
+ *
+ * \param[in] zone Zone to search in.
+ * \param[in] name Domain name to get the corresponding NSEC3 nodes for.
+ * \param[out] nsec3_node NSEC3 node corresponding to \a name (if found,
+ * otherwise this may be an arbitrary NSEC3 node).
+ * \param[out] nsec3_previous The NSEC3 node immediately preceding hashed domain
+ * name corresponding to \a name in canonical order.
+ *
+ * \retval KNOT_ZONE_NAME_FOUND if the corresponding NSEC3 node was found.
+ * \retval KNOT_ZONE_NAME_NOT_FOUND if it was not found.
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENSEC3PAR
+ * \retval KNOT_ECRYPTO
+ * \retval KNOT_ERROR
+ */
+int knot_zone_contents_find_nsec3_for_name(
+ const knot_zone_contents_t *contents,
+ const knot_dname_t *name,
+ const knot_node_t **nsec3_node,
+ const knot_node_t **nsec3_previous,
+ int check_ver);
+/*!
+ * \brief Returns the apex node of the zone.
+ *
+ * \param zone Zone to get the apex of.
+ *
+ * \return Zone apex node.
+ */
+const knot_node_t *knot_zone_contents_apex(
+ const knot_zone_contents_t *contents);
+
+knot_node_t *knot_zone_contents_get_apex(
+ const knot_zone_contents_t *contents);
+
+//knot_dname_t *knot_zone_contents_name(
+// const knot_zone_contents_t *contents);
+
+/*!
+ * \brief Optimizes zone by replacing domain names in RDATA with references to
+ * domain names present in zone (as node owners).
+ *
+ * \param zone Zone to adjust domain names in.
+ */
+int knot_zone_contents_adjust(knot_zone_contents_t *contents, int check_ver);
+
+/*!
+ * \brief Parses the NSEC3PARAM record stored in the zone.
+ *
+ * This function properly fills in the nsec3_params field of the zone structure
+ * according to data stored in the NSEC3PARAM record. This is necessary to do
+ * before any NSEC3 operations on the zone are requested, otherwise they will
+ * fail (error KNOT_ENSEC3PAR).
+ *
+ * \note If there is no NSEC3PARAM record in the zone, this function clears
+ * the nsec3_params field of the zone structure (fills it with zeros).
+ *
+ * \param zone Zone to get the NSEC3PARAM record from.
+ */
+int knot_zone_contents_load_nsec3param(knot_zone_contents_t *contents);
+
+/*!
+ * \brief Checks if the zone uses NSEC3.
+ *
+ * This function will return 0 if the NSEC3PARAM record was not parse prior to
+ * calling it.
+ *
+ * \param zone Zone to check.
+ *
+ * \retval <> 0 if the zone uses NSEC3.
+ * \retval 0 if it does not.
+ *
+ * \see knot_zone_contents_load_nsec3param()
+ */
+int knot_zone_contents_nsec3_enabled(const knot_zone_contents_t *contents);
+
+/*!
+ * \brief Returns the parsed NSEC3PARAM record of the zone.
+ *
+ * \note You must parse the NSEC3PARAM record prior to calling this function
+ * (knot_zone_contents_load_nsec3param()).
+ *
+ * \param zone Zone to get the NSEC3PARAM record from.
+ *
+ * \return Parsed NSEC3PARAM from the zone or NULL if the zone does not use
+ * NSEC3 or the record was not parsed before.
+ *
+ * \see knot_zone_contents_load_nsec3param()
+ */
+const knot_nsec3_params_t *knot_zone_contents_nsec3params(
+ const knot_zone_contents_t *contents);
+
+/*!
+ * \brief Applies the given function to each regular node in the zone.
+ *
+ * This function uses post-order depth-first forward traversal, i.e. the
+ * function is first recursively applied to subtrees and then to the root.
+ *
+ * \param zone Nodes of this zone will be used as parameters for the function.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ */
+int knot_zone_contents_tree_apply_postorder(knot_zone_contents_t *contents,
+ void (*function)(knot_node_t *node, void *data),
+ void *data);
+
+/*!
+ * \brief Applies the given function to each regular node in the zone.
+ *
+ * This function uses in-order depth-first forward traversal, i.e. the function
+ * is first recursively applied to left subtree, then to the root and then to
+ * the right subtree.
+ *
+ * \note This implies that the zone is stored in a binary tree. Is there a way
+ * to make this traversal independent on the underlying structure?
+ *
+ * \param zone Nodes of this zone will be used as parameters for the function.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ */
+int knot_zone_contents_tree_apply_inorder(knot_zone_contents_t *contents,
+ void (*function)(knot_node_t *node, void *data),
+ void *data);
+
+/*!
+ * \brief Applies the given function to each regular node in the zone.
+ *
+ * This function uses in-order depth-first reverse traversal, i.e. the function
+ * is first recursively applied to right subtree, then to the root and then to
+ * the left subtree.
+ *
+ * \note This implies that the zone is stored in a binary tree. Is there a way
+ * to make this traversal independent on the underlying structure?
+ *
+ * \param zone Nodes of this zone will be used as parameters for the function.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ */
+int knot_zone_contents_tree_apply_inorder_reverse(
+ knot_zone_contents_t *contents,
+ void (*function)(knot_node_t *node, void *data), void *data);
+
+/*!
+ * \brief Applies the given function to each NSEC3 node in the zone.
+ *
+ * This function uses post-order depth-first forward traversal, i.e. the
+ * function is first recursively applied to subtrees and then to the root.
+ *
+ * \param zone NSEC3 nodes of this zone will be used as parameters for the
+ * function.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ */
+int knot_zone_contents_nsec3_apply_postorder(knot_zone_contents_t *contents,
+ void (*function)(knot_node_t *node, void *data),
+ void *data);
+
+/*!
+ * \brief Applies the given function to each NSEC3 node in the zone.
+ *
+ * This function uses in-order depth-first forward traversal, i.e. the function
+ * is first recursively applied to left subtree, then to the root and then to
+ * the right subtree.
+ *
+ * \note This implies that the zone is stored in a binary tree. Is there a way
+ * to make this traversal independent on the underlying structure?
+ *
+ * \param zone NSEC3 nodes of this zone will be used as parameters for the
+ * function.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ */
+int knot_zone_contents_nsec3_apply_inorder(knot_zone_contents_t *contents,
+ void (*function)(knot_node_t *node, void *data),
+ void *data);
+
+/*!
+ * \brief Applies the given function to each NSEC3 node in the zone.
+ *
+ * This function uses in-order depth-first reverse traversal, i.e. the function
+ * is first recursively applied to right subtree, then to the root and then to
+ * the left subtree.
+ *
+ * \note This implies that the zone is stored in a binary tree. Is there a way
+ * to make this traversal independent on the underlying structure?
+ *
+ * \param zone NSEC3 nodes of this zone will be used as parameters for the
+ * function.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ */
+int knot_zone_contents_nsec3_apply_inorder_reverse(
+ knot_zone_contents_t *contents,
+ void (*function)(knot_node_t *node, void *data), void *data);
+
+knot_zone_tree_t *knot_zone_contents_get_nodes(
+ knot_zone_contents_t *contents);
+
+knot_zone_tree_t *knot_zone_contents_get_nsec3_nodes(
+ knot_zone_contents_t *contents);
+
+ck_hash_table_t *knot_zone_contents_get_hash_table(
+ knot_zone_contents_t *contents);
+
+int knot_zone_contents_dname_table_apply(knot_zone_contents_t *contents,
+ void (*function)(knot_dname_t *,
+ void *),
+ void *data);
+
+/*!
+ * \brief Creates a shallow copy of the zone (no stored data are copied).
+ *
+ * This function creates a new zone structure in \a to, creates new trees for
+ * regular nodes and for NSEC3 nodes, creates new hash table and a new domain
+ * table. It also fills these structures with the exact same data as the
+ * original zone is - no copying of stored data is done, just pointers are
+ * copied.
+ *
+ * \param from Original zone.
+ * \param to Copy of the zone.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ */
+int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from,
+ knot_zone_contents_t **to);
+
+void knot_zone_contents_free(knot_zone_contents_t **contents);
+
+void knot_zone_contents_deep_free(knot_zone_contents_t **contents,
+ int destroy_dname_table);
+
+#endif
+
+/*! @} */
diff --git a/src/libknot/zone/zone-tree.c b/src/libknot/zone/zone-tree.c
new file mode 100644
index 0000000..cdf128e
--- /dev/null
+++ b/src/libknot/zone/zone-tree.c
@@ -0,0 +1,470 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "zone-tree.h"
+#include "zone/node.h"
+#include "util/error.h"
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+
+// AVL tree functions
+TREE_DEFINE(knot_zone_tree_node, avl);
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_zone_tree_node_compare(knot_zone_tree_node_t *node1,
+ knot_zone_tree_node_t *node2)
+{
+ assert(node1 != NULL);
+ assert(node2 != NULL);
+ assert(node1->node != NULL);
+ assert(node2->node != NULL);
+ assert(knot_node_owner(node1->node) != NULL);
+ assert(knot_node_owner(node2->node) != NULL);
+
+ return knot_node_compare(node1->node, node2->node);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void knot_zone_tree_delete_subtree(knot_zone_tree_node_t *root)
+{
+ if (root == NULL) {
+ return;
+ }
+
+ knot_zone_tree_delete_subtree(root->avl.avl_left);
+ knot_zone_tree_delete_subtree(root->avl.avl_right);
+ free(root);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int knot_zone_tree_copy_node(knot_zone_tree_node_t *from,
+ knot_zone_tree_node_t **to)
+{
+ if (from == NULL) {
+ *to = NULL;
+ return KNOT_EOK;
+ }
+
+ *to = (knot_zone_tree_node_t *)
+ malloc(sizeof(knot_zone_tree_node_t));
+ if (*to == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ (*to)->node = from->node;
+ (*to)->avl.avl_height = from->avl.avl_height;
+
+ int ret = knot_zone_tree_copy_node(from->avl.avl_left,
+ &(*to)->avl.avl_left);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ ret = knot_zone_tree_copy_node(from->avl.avl_right,
+ &(*to)->avl.avl_right);
+ if (ret != KNOT_EOK) {
+ knot_zone_tree_delete_subtree((*to)->avl.avl_left);
+ (*to)->avl.avl_left = NULL;
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void knot_zone_tree_free_node(knot_zone_tree_node_t *node,
+ int free_data, int free_owner)
+{
+ if (node == NULL) {
+ return;
+ }
+
+ knot_zone_tree_free_node(node->avl.avl_left, free_data, free_owner);
+
+ knot_zone_tree_free_node(node->avl.avl_right, free_data, free_owner);
+
+ if (free_data) {
+ knot_node_free(&node->node, free_owner, 0);
+ }
+
+ free(node);
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_init(knot_zone_tree_t *tree)
+{
+ if (tree == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ TREE_INIT(tree, knot_zone_tree_node_compare);
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_insert(knot_zone_tree_t *tree, knot_node_t *node)
+{
+ if (tree == NULL || node == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_tree_node_t *znode = (knot_zone_tree_node_t *)malloc(
+ sizeof(knot_zone_tree_node_t));
+ if (znode == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ znode->node = node;
+ znode->avl.avl_left = NULL;
+ znode->avl.avl_right = NULL;
+ znode->avl.avl_height = 0;
+
+ /*! \todo How to know if this was successful? */
+ TREE_INSERT(tree, knot_zone_tree_node, avl, znode);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_find(knot_zone_tree_t *tree, const knot_dname_t *owner,
+ const knot_node_t **found)
+{
+ if (tree == NULL || owner == NULL || found == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_node_t *f = NULL;
+ int ret = knot_zone_tree_get(tree, owner, &f);
+ *found = f;
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_get(knot_zone_tree_t *tree, const knot_dname_t *owner,
+ knot_node_t **found)
+{
+ if (tree == NULL || owner == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ *found = NULL;
+
+ // create dummy node to use for lookup
+ knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc(
+ sizeof(knot_zone_tree_node_t));
+ if (tmp == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // create dummy data node to use for lookup
+ knot_node_t *tmp_data = knot_node_new(
+ (knot_dname_t *)owner, NULL, 0);
+ if (tmp_data == NULL) {
+ free(tmp);
+ return KNOT_ENOMEM;
+ }
+ tmp->node = tmp_data;
+
+ knot_zone_tree_node_t *n = TREE_FIND(tree, knot_zone_tree_node, avl,
+ tmp);
+
+ knot_node_free(&tmp_data, 0, 0);
+ free(tmp);
+
+ if (n != NULL) {
+ *found = n->node;
+ }
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_find_less_or_equal(knot_zone_tree_t *tree,
+ const knot_dname_t *owner,
+ const knot_node_t **found,
+ const knot_node_t **previous,
+ int check_version)
+{
+ if (tree == NULL || owner == NULL || found == NULL || previous == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_node_t *f, *p;
+ int ret = knot_zone_tree_get_less_or_equal(tree, owner, &f, &p, check_version);
+
+ *found = f;
+ *previous = p;
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree,
+ const knot_dname_t *owner,
+ knot_node_t **found,
+ knot_node_t **previous,
+ int check_version)
+{
+ if (tree == NULL || owner == NULL || found == NULL
+ || previous == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ knot_zone_tree_node_t *f = NULL, *prev = NULL;
+
+ // create dummy node to use for lookup
+ knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc(
+ sizeof(knot_zone_tree_node_t));
+ if (tmp == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // create dummy data node to use for lookup
+ knot_node_t *tmp_data = knot_node_new(
+ (knot_dname_t *)owner, NULL, 0);
+ if (tmp_data == NULL) {
+ free(tmp);
+ return KNOT_ENOMEM;
+ }
+ tmp->node = tmp_data;
+
+ int exact_match = TREE_FIND_LESS_EQUAL(
+ tree, knot_zone_tree_node, avl, tmp, &f, &prev);
+
+ knot_node_free(&tmp_data, 0, 0);
+ free(tmp);
+
+ *found = (exact_match > 0) ? f->node : NULL;
+
+ if (exact_match < 0) {
+ // previous is not really previous but should be the leftmost
+ // node in the tree; take it's previous
+ assert(prev != NULL);
+ *previous = knot_node_get_previous(prev->node, check_version);
+ exact_match = 0;
+ } else if (prev == NULL) {
+ if (!exact_match) {
+ printf("Searched for owner %s in zone tree.\n",
+ knot_dname_to_str(owner));
+ printf("Exact match: %d\n", exact_match);
+ printf("Found node: %p: %s.\n", f, (f)
+ ? knot_dname_to_str(knot_node_owner(f->node))
+ : "none");
+ printf("Previous node: %p: %s.\n", prev, (prev)
+ ? knot_dname_to_str(knot_node_owner(prev->node))
+ : "none");
+ }
+
+ // either the returned node is the root of the tree, or
+ // it is the leftmost node in the tree; in both cases
+ // node was found set the previous node of the found
+ // node
+ assert(exact_match > 0);
+ assert(f != NULL);
+ *previous = knot_node_get_previous(f->node, check_version);
+ } else {
+ // otherwise check if the previous node is not an empty
+ // non-terminal
+ /*! \todo Here we assume that the 'prev' pointer always points
+ * to an empty non-terminal.
+ */
+ *previous = (knot_node_rrset_count(prev->node) == 0)
+ ? knot_node_get_previous(prev->node, check_version)
+ : prev->node;
+ }
+
+ assert(exact_match >= 0);
+
+ return exact_match;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_remove(knot_zone_tree_t *tree,
+ const knot_dname_t *owner,
+ knot_zone_tree_node_t **removed)
+{
+ if (tree == NULL || owner == NULL || removed == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ // create dummy node to use for lookup
+ knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc(
+ sizeof(knot_zone_tree_node_t));
+ if (tmp == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ // create dummy data node to use for lookup
+ knot_node_t *tmp_data = knot_node_new(
+ (knot_dname_t *)owner, NULL, 0);
+ if (tmp_data == NULL) {
+ free(tmp);
+ return KNOT_ENOMEM;
+ }
+ tmp->node = tmp_data;
+
+ // we must first find the node, so that it may be destroyed
+ knot_zone_tree_node_t *n = TREE_FIND(tree, knot_zone_tree_node, avl,
+ tmp);
+
+ /*! \todo How to know if this was successful? */
+ TREE_REMOVE(tree, knot_zone_tree_node, avl, tmp);
+
+ knot_node_free(&tmp_data, 0, 0);
+ free(tmp);
+
+// *removed = (n) ? n->node : NULL;
+// free(n);
+ *removed = n;
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_forward_apply_inorder(knot_zone_tree_t *tree,
+ void (*function)(
+ knot_zone_tree_node_t *node,
+ void *data),
+ void *data)
+{
+ if (tree == NULL || function == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ TREE_FORWARD_APPLY(tree, knot_zone_tree_node, avl,
+ function, data);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_forward_apply_postorder(knot_zone_tree_t *tree,
+ void (*function)(
+ knot_zone_tree_node_t *node,
+ void *data),
+ void *data)
+{
+ if (tree == NULL || function == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ TREE_POST_ORDER_APPLY(tree, knot_zone_tree_node, avl,
+ function, data);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_reverse_apply_inorder(knot_zone_tree_t *tree,
+ void (*function)(
+ knot_zone_tree_node_t *node,
+ void *data),
+ void *data)
+{
+ if (tree == NULL || function == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ TREE_REVERSE_APPLY(tree, knot_zone_tree_node, avl,
+ function, data);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_reverse_apply_postorder(knot_zone_tree_t *tree,
+ void (*function)(
+ knot_zone_tree_node_t *node,
+ void *data),
+ void *data)
+{
+ if (tree == NULL || function == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ TREE_REVERSE_APPLY_POST(tree, knot_zone_tree_node, avl,
+ function, data);
+
+ return KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zone_tree_shallow_copy(knot_zone_tree_t *from,
+ knot_zone_tree_t *to)
+{
+ if (to == NULL || from == NULL) {
+ return KNOT_EBADARG;
+ }
+ /*
+ * This function will copy the tree by hand, so that the nodes
+ * do not have to be inserted the normal way. It should be substantially
+ * faster.
+ */
+
+ to->th_cmp = from->th_cmp;
+
+ return knot_zone_tree_copy_node(from->th_root, &to->th_root);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_tree_free(knot_zone_tree_t **tree)
+{
+ if (tree == NULL || *tree == NULL) {
+ return;
+ }
+ knot_zone_tree_free_node((*tree)->th_root, 0, 0);
+ free(*tree);
+ *tree = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_tree_deep_free(knot_zone_tree_t **tree, int free_owners)
+{
+ if (tree == NULL || *tree == NULL) {
+ return;
+ }
+ knot_zone_tree_free_node((*tree)->th_root, 1, free_owners);
+ free(*tree);
+ *tree = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
diff --git a/src/libknot/zone/zone-tree.h b/src/libknot/zone/zone-tree.h
new file mode 100644
index 0000000..0971749
--- /dev/null
+++ b/src/libknot/zone/zone-tree.h
@@ -0,0 +1,300 @@
+/*!
+ * \file zone-tree.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Zone tree structure and API for manipulating it.
+ *
+ * Implemented as AVL tree.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_ZONE_TREE_H_
+#define _KNOT_ZONE_TREE_H_
+
+#include "common/tree.h"
+#include "zone/node.h"
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct knot_zone_tree_node {
+ /*! \brief Structure for connecting this node to an AVL tree. */
+ TREE_ENTRY(knot_zone_tree_node) avl;
+ /*! \brief Zone tree data. */
+ knot_node_t *node;
+ /*! \brief Owner of the node. */
+// knot_dname_t *owner;
+} knot_zone_tree_node_t;
+
+/*----------------------------------------------------------------------------*/
+
+typedef TREE_HEAD(knot_zone_tree, knot_zone_tree_node) knot_zone_tree_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Initializes the zone tree.
+ *
+ * Does not allocate the structure. Must be called before any use of the tree.
+ *
+ * \param tree Zone tree structure to initialize.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ */
+int knot_zone_tree_init(knot_zone_tree_t *tree);
+
+/*!
+ * \brief Inserts the given node into the zone tree.
+ *
+ * \param tree Zone tree to insert the node into.
+ * \param node Node to insert.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ */
+int knot_zone_tree_insert(knot_zone_tree_t *tree, knot_node_t *node);
+
+/*!
+ * \brief Finds node with the given owner in the zone tree.
+ *
+ * \param tree Zone tree to search in.
+ * \param owner Owner of the node to find.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ */
+int knot_zone_tree_find(knot_zone_tree_t *tree,
+ const knot_dname_t *owner,
+ const knot_node_t **found);
+
+/*!
+ * \brief Finds node with the given owner in the zone tree.
+ *
+ * \note This function is identical to knot_zone_tree_find() except that it
+ * returns non-const node.
+ *
+ * \param tree Zone tree to search in.
+ * \param owner Owner of the node to find.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ */
+int knot_zone_tree_get(knot_zone_tree_t *tree,
+ const knot_dname_t *owner,
+ knot_node_t **found);
+
+/*!
+ * \brief Tries to find the given domain name in the zone tree and returns the
+ * associated node and previous node in canonical order.
+ *
+ * \param zone Zone to search in.
+ * \param owner Owner of the node to find.
+ * \param found Found node.
+ * \param previous Previous node in canonical order (i.e. the one directly
+ * preceding \a owner in canonical order, regardless if the name
+ * is in the zone or not).
+ *
+ * \retval > 0 if the domain name was found. In such case \a found holds the
+ * zone node with \a owner as its owner.
+ * \a previous is set properly.
+ * \retval 0 if the domain name was not found. \a found may hold any (or none)
+ * node. \a previous is set properly.
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ */
+int knot_zone_tree_find_less_or_equal(knot_zone_tree_t *tree,
+ const knot_dname_t *owner,
+ const knot_node_t **found,
+ const knot_node_t **previous,
+ int check_version);
+
+/*!
+ * \brief Tries to find the given domain name in the zone tree and returns the
+ * associated node and previous node in canonical order.
+ *
+ * \note This function is identical to knot_zone_tree_find_less_or_equal()
+ * except that it returns non-const nodes.
+ *
+ * \param zone Zone to search in.
+ * \param owner Owner of the node to find.
+ * \param found Found node.
+ * \param previous Previous node in canonical order (i.e. the one directly
+ * preceding \a owner in canonical order, regardless if the name
+ * is in the zone or not).
+ *
+ * \retval > 0 if the domain name was found. In such case \a found holds the
+ * zone node with \a owner as its owner.
+ * \a previous is set properly.
+ * \retval 0 if the domain name was not found. \a found may hold any (or none)
+ * node. \a previous is set properly.
+ * \retval KNOT_EBADARG
+ * \retval KNOT_ENOMEM
+ */
+int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree,
+ const knot_dname_t *owner,
+ knot_node_t **found,
+ knot_node_t **previous,
+ int check_version);
+
+/*!
+ * \brief Removes node with the given owner from the zone tree and returns it.
+ *
+ * \param tree Zone tree to remove the node from.
+ * \param owner Owner of the node to find.
+ * \param removed The removed node.
+ *
+ * \retval The removed node.
+ */
+int knot_zone_tree_remove(knot_zone_tree_t *tree,
+ const knot_dname_t *owner,
+ knot_zone_tree_node_t **removed);
+
+/*!
+ * \brief Applies the given function to each node in the zone.
+ *
+ * This function uses in-order depth-first forward traversal, i.e. the function
+ * is first recursively applied to left subtree, then to the root and then to
+ * the right subtree.
+ *
+ * \note This implies that the zone is stored in a binary tree. Is there a way
+ * to make this traversal independent on the underlying structure?
+ *
+ * \param tree Zone tree to apply the function to.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ */
+int knot_zone_tree_forward_apply_inorder(knot_zone_tree_t *tree,
+ void (*function)(
+ knot_zone_tree_node_t *node,
+ void *data),
+ void *data);
+
+/*!
+ * \brief Applies the given function to each node in the zone.
+ *
+ * This function uses post-order depth-first forward traversal, i.e. the
+ * function is first recursively applied to subtrees and then to the root.
+ *
+ * \note This implies that the zone is stored in a binary tree. Is there a way
+ * to make this traversal independent on the underlying structure?
+ *
+ * \param tree Zone tree to apply the function to.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ */
+int knot_zone_tree_forward_apply_postorder(knot_zone_tree_t *tree,
+ void (*function)(
+ knot_zone_tree_node_t *node,
+ void *data),
+ void *data);
+
+/*!
+ * \brief Applies the given function to each node in the zone.
+ *
+ * This function uses in-order depth-first reverse traversal, i.e. the function
+ * is first recursively applied to right subtree, then to the root and then to
+ * the left subtree.
+ *
+ * \note This implies that the zone is stored in a binary tree. Is there a way
+ * to make this traversal independent on the underlying structure?
+ *
+ * \param tree Zone tree to apply the function to.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ */
+int knot_zone_tree_reverse_apply_inorder(knot_zone_tree_t *tree,
+ void (*function)(
+ knot_zone_tree_node_t *node,
+ void *data),
+ void *data);
+
+/*!
+ * \brief Applies the given function to each node in the zone.
+ *
+ * This function uses post-order depth-first reverse traversal, i.e. the
+ * function is first recursively applied to right subtree, then to the
+ * left subtree and then to the root.
+ *
+ * \note This implies that the zone is stored in a binary tree. Is there a way
+ * to make this traversal independent on the underlying structure?
+ *
+ * \param tree Zone tree to apply the function to.
+ * \param function Function to be applied to each node of the zone.
+ * \param data Arbitrary data to be passed to the function.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EBADARG
+ */
+int knot_zone_tree_reverse_apply_postorder(knot_zone_tree_t *tree,
+ void (*function)(
+ knot_zone_tree_node_t *node,
+ void *data),
+ void *data);
+
+/*!
+ * \brief Copies the whole zone tree structure (but not the data contained
+ * within).
+ *
+ * \warning This function does not check if the target zone tree is empty,
+ * it just replaces the root pointer.
+ *
+ * \param from Original zone tree.
+ * \param to Zone tree to copy the original one into.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOMEM
+ */
+int knot_zone_tree_shallow_copy(knot_zone_tree_t *from,
+ knot_zone_tree_t *to);
+
+/*!
+ * \brief Destroys the zone tree, not touching the saved data.
+ *
+ * \param tree Zone tree to be destroyed.
+ */
+void knot_zone_tree_free(knot_zone_tree_t **tree);
+
+/*!
+ * \brief Destroys the zone tree, together with the saved data.
+ *
+ * \param tree Zone tree to be destroyed.
+ * \param free_owners Set to <> 0 if owners of the nodes should be destroyed
+ * as well. Set to 0 otherwise.
+ */
+void knot_zone_tree_deep_free(knot_zone_tree_t **tree, int free_owners);
+
+/*----------------------------------------------------------------------------*/
+
+#endif // _KNOT_ZONE_TREE_H_
+
+/*! @} */
+
diff --git a/src/libknot/zone/zone.c b/src/libknot/zone/zone.c
new file mode 100644
index 0000000..9de1a53
--- /dev/null
+++ b/src/libknot/zone/zone.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <urcu.h>
+
+#include "common.h"
+#include "zone/zone.h"
+#include "zone/node.h"
+#include "dname.h"
+#include "consts.h"
+#include "util/descriptor.h"
+#include "nsec3.h"
+#include "util/error.h"
+#include "util/debug.h"
+#include "util/utils.h"
+#include "common/tree.h"
+#include "common/base32hex.h"
+#include "hash/cuckoo-hash-table.h"
+#include "zone/zone-contents.h"
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+knot_zone_t *knot_zone_new_empty(knot_dname_t *name)
+{
+ if (!name) {
+ return 0;
+ }
+
+ dbg_zone("Creating new zone!\n");
+
+ knot_zone_t *zone = malloc(sizeof(knot_zone_t));
+ if (zone == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ memset(zone, 0, sizeof(knot_zone_t));
+
+ // save the zone name
+ dbg_zone("Setting zone name.\n");
+ zone->name = name;
+ return zone;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_t *knot_zone_new(knot_node_t *apex, uint node_count,
+ int use_domain_table)
+{
+ knot_zone_t *zone = knot_zone_new_empty(
+ knot_dname_deep_copy(knot_node_owner(apex)));
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ dbg_zone("Creating zone contents.\n");
+ zone->contents = knot_zone_contents_new(apex, node_count,
+ use_domain_table, zone);
+ if (zone->contents == NULL) {
+ knot_dname_release(zone->name);
+ free(zone);
+ return NULL;
+ }
+
+ zone->contents->zone = zone;
+
+ return zone;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_contents_t *knot_zone_get_contents(
+ const knot_zone_t *zone)
+{
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ return rcu_dereference(zone->contents);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_zone_contents_t *knot_zone_contents(
+ const knot_zone_t *zone)
+{
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ return rcu_dereference(zone->contents);
+}
+
+/*----------------------------------------------------------------------------*/
+
+time_t knot_zone_version(const knot_zone_t *zone)
+{
+ if (zone == NULL) {
+ return KNOT_EBADARG;
+ }
+
+ return zone->version;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_set_version(knot_zone_t *zone, time_t version)
+{
+ if (zone == NULL) {
+ return;
+ }
+
+ zone->version = version;
+}
+
+/*----------------------------------------------------------------------------*/
+
+short knot_zone_is_master(const knot_zone_t *zone)
+{
+ return zone->master;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_set_master(knot_zone_t *zone, short master)
+{
+ zone->master = master;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const void *knot_zone_data(const knot_zone_t *zone)
+{
+ return zone->data;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_set_data(knot_zone_t *zone, void *data)
+{
+ zone->data = data;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_zone_name(const knot_zone_t *zone)
+{
+ return zone->name;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_contents_t *knot_zone_switch_contents(knot_zone_t *zone,
+ knot_zone_contents_t *new_contents)
+{
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ knot_zone_contents_t *old_contents =
+ rcu_xchg_pointer(&zone->contents, new_contents);
+ return old_contents;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_free(knot_zone_t **zone)
+{
+ if (zone == NULL || *zone == NULL) {
+ return;
+ }
+
+ dbg_zone("zone_free().\n");
+
+ if ((*zone)->contents
+ && !knot_zone_contents_gen_is_old((*zone)->contents)) {
+ // zone is in the middle of an update, report
+ dbg_zone("Destroying zone that is in the middle of an "
+ "update.\n");
+ }
+
+ knot_dname_release((*zone)->name);
+
+ /* Call zone data destructor if exists. */
+ if ((*zone)->dtor) {
+ (*zone)->dtor(*zone);
+ }
+
+ knot_zone_contents_free(&(*zone)->contents);
+ free(*zone);
+ *zone = NULL;
+
+ dbg_zone("Done.\n");
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zone_deep_free(knot_zone_t **zone, int destroy_dname_table)
+{
+ if (zone == NULL || *zone == NULL) {
+ return;
+ }
+
+ if ((*zone)->contents
+ && !knot_zone_contents_gen_is_old((*zone)->contents)) {
+ // zone is in the middle of an update, report
+ dbg_zone("Destroying zone that is in the middle of an "
+ "update.\n");
+ }
+
+dbg_zone_exec(
+ char *name = knot_dname_to_str((*zone)->name);
+ dbg_zone("Destroying zone %p, name: %s.\n", *zone, name);
+ free(name);
+);
+
+ knot_dname_release((*zone)->name);
+
+ /* Call zone data destructor if exists. */
+ if ((*zone)->dtor) {
+ (*zone)->dtor(*zone);
+ }
+
+ knot_zone_contents_deep_free(&(*zone)->contents, destroy_dname_table);
+ free(*zone);
+ *zone = NULL;
+}
diff --git a/src/libknot/zone/zone.h b/src/libknot/zone/zone.h
new file mode 100644
index 0000000..331ef1f
--- /dev/null
+++ b/src/libknot/zone/zone.h
@@ -0,0 +1,157 @@
+/*!
+ * \file zone.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Zone structure and API for manipulating it.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_ZONE_H_
+#define _KNOT_ZONE_H_
+
+#include <time.h>
+
+#include "zone/node.h"
+#include "dname.h"
+#include "nsec3.h"
+#include "zone/dname-table.h"
+#include "common/tree.h"
+#include "hash/cuckoo-hash-table.h"
+
+#include "zone-tree.h"
+
+#include "zone/zone-contents.h"
+
+/*----------------------------------------------------------------------------*/
+
+//typedef TREE_HEAD(avl_tree, knot_node) avl_tree_t;
+//struct event_t;
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Return values for search functions.
+ *
+ * Used in knot_zone_find_dname() and knot_zone_find_dname_hash().
+ */
+enum knot_zone_retvals {
+ KNOT_ZONE_NAME_FOUND = 1,
+ KNOT_ZONE_NAME_NOT_FOUND = 0
+};
+
+typedef enum knot_zone_retvals knot_zone_retvals_t;
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Structure for holding DNS zone.
+ *
+ * \warning Make sure not to insert the same nodes using both the normal and
+ * NSEC3 functions. Although this will be successfull, it will produce
+ * double-free errors when destroying the zone.
+ */
+struct knot_zone {
+ knot_dname_t *name;
+
+ knot_zone_contents_t *contents;
+
+ time_t version;
+
+ /*! \todo Set when loading zone. */
+ short master;
+
+ void *data; /*!< Pointer to generic zone-related data. */
+ int (*dtor)(struct knot_zone *); /*!< Data destructor. */
+};
+
+typedef struct knot_zone knot_zone_t;
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Creates new empty DNS zone.
+ *
+ * \notice Zone will be created without contents.
+ *
+ * \param name Zone owner.
+ *
+ * \return The initialized zone structure or NULL if an error occured.
+ */
+knot_zone_t *knot_zone_new_empty(knot_dname_t *name);
+
+/*!
+ * \brief Creates new DNS zone.
+ *
+ * \param apex Node representing the zone apex.
+ * \param node_count Number of authorative nodes in the zone.
+ *
+ * \return The initialized zone structure or NULL if an error occured.
+ */
+knot_zone_t *knot_zone_new(knot_node_t *apex, uint node_count,
+ int use_domain_table);
+
+knot_zone_contents_t *knot_zone_get_contents(
+ const knot_zone_t *zone);
+
+const knot_zone_contents_t *knot_zone_contents(
+ const knot_zone_t *zone);
+
+
+time_t knot_zone_version(const knot_zone_t *zone);
+
+void knot_zone_set_version(knot_zone_t *zone, time_t version);
+
+short knot_zone_is_master(const knot_zone_t *zone);
+
+void knot_zone_set_master(knot_zone_t *zone, short master);
+
+const void *knot_zone_data(const knot_zone_t *zone);
+
+void knot_zone_set_data(knot_zone_t *zone, void *data);
+
+const knot_dname_t *knot_zone_name(const knot_zone_t *zone);
+
+knot_zone_contents_t *knot_zone_switch_contents(knot_zone_t *zone,
+ knot_zone_contents_t *new_contents);
+
+/*!
+ * \brief Correctly deallocates the zone structure, without deleting its nodes.
+ *
+ * Also sets the given pointer to NULL.
+ *
+ * \param zone Zone to be freed.
+ */
+void knot_zone_free(knot_zone_t **zone);
+
+/*!
+ * \brief Correctly deallocates the zone structure and all nodes within.
+ *
+ * Also sets the given pointer to NULL.
+ *
+ * \param zone Zone to be freed.
+ * \param free_rdata_dnames Set to <> 0 if you want to delete ALL domain names
+ * present in RDATA. Set to 0 otherwise. (See
+ * knot_rdata_deep_free().)
+ */
+void knot_zone_deep_free(knot_zone_t **zone, int destroy_dname_table);
+
+#endif
+
+/*! @} */
diff --git a/src/libknot/zone/zonedb.c b/src/libknot/zone/zonedb.c
new file mode 100644
index 0000000..8f07d45
--- /dev/null
+++ b/src/libknot/zone/zonedb.c
@@ -0,0 +1,389 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <urcu.h>
+
+#include "common.h"
+#include "zone/zone.h"
+#include "zone/zonedb.h"
+#include "dname.h"
+#include "zone/node.h"
+#include "util/error.h"
+#include "util/debug.h"
+#include "common/general-tree.h"
+
+/*----------------------------------------------------------------------------*/
+/* Non-API functions */
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Compares the two arguments interpreted as zone names (domain names).
+ *
+ * Use this function with generic data structures (such as the skip list).
+ *
+ * \param d1 First zone name.
+ * \param d2 Second zone name.
+ *
+ * \retval 0 if the two zone names are equal.
+ * \retval < 0 if \a d1 is before \a d2 in canonical order.
+ * \retval > 0 if \a d1 is after \a d2 in canonical order.
+ */
+static int knot_zonedb_compare_zone_names(void *p1, void *p2)
+{
+ const knot_zone_t *zone1 = (const knot_zone_t *)p1;
+ const knot_zone_t *zone2 = (const knot_zone_t *)p2;
+
+ int ret = knot_dname_compare(zone1->name, zone2->name);
+
+dbg_zonedb_exec(
+ char *name1 = knot_dname_to_str(zone1->name);
+ char *name2 = knot_dname_to_str(zone2->name);
+ dbg_zonedb("Compared names %s and %s, result: %d.\n",
+ name1, name2, ret);
+ free(name1);
+ free(name2);
+);
+
+ return (ret);
+}
+
+/*----------------------------------------------------------------------------*/
+
+//static int knot_zonedb_replace_zone_in_list(void **list_item, void **new_zone)
+//{
+// assert(list_item != NULL);
+// assert(*list_item != NULL);
+// assert(new_zone != NULL);
+// assert(*new_zone != NULL);
+
+// dbg_zonedb("Replacing list item %p with new zone %p\n",
+// *list_item, *new_zone);
+
+// *list_item = *new_zone;
+
+// return 0;
+//}
+
+/*----------------------------------------------------------------------------*/
+/* API functions */
+/*----------------------------------------------------------------------------*/
+
+knot_zonedb_t *knot_zonedb_new()
+{
+ knot_zonedb_t *db =
+ (knot_zonedb_t *)malloc(sizeof(knot_zonedb_t));
+ CHECK_ALLOC_LOG(db, NULL);
+
+ db->zone_tree = gen_tree_new(knot_zonedb_compare_zone_names);
+ if (db->zone_tree == NULL) {
+ free(db);
+ return NULL;
+ }
+
+ db->zone_count = 0;
+
+ return db;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int knot_zonedb_add_zone(knot_zonedb_t *db, knot_zone_t *zone)
+{
+ if (db == NULL || zone == NULL) {
+ return KNOT_EBADARG;
+ }
+dbg_zonedb_exec(
+ char *name = knot_dname_to_str(zone->name);
+ dbg_zonedb("Inserting zone %s into zone db.\n", name);
+ free(name);
+);
+
+ int ret = KNOT_EOK;
+ if (knot_zone_contents(zone)) {
+ ret = knot_zone_contents_load_nsec3param(
+ knot_zone_get_contents(zone));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ ret = gen_tree_add(db->zone_tree, zone, NULL);
+
+ if (ret == 0) {
+ db->zone_count++;
+ }
+
+ return (ret != 0) ? KNOT_EZONEIN : KNOT_EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_t *knot_zonedb_remove_zone(knot_zonedb_t *db,
+ const knot_dname_t *zone_name)
+{
+ knot_zone_t dummy_zone;
+ memset(&dummy_zone, 0, sizeof(knot_zone_t));
+ dummy_zone.name = (knot_dname_t *)zone_name;
+
+ // add some lock to avoid multiple removals
+ knot_zone_t *z = (knot_zone_t *)gen_tree_find(db->zone_tree,
+ &dummy_zone);
+
+ if (z == NULL) {
+ return NULL;
+ }
+
+ // remove the zone from the skip list, but do not destroy it
+ gen_tree_remove(db->zone_tree, &dummy_zone);
+
+// if (destroy_zone) {
+// // properly destroy the zone and all its contents
+// knot_zone_deep_free(&z, 0);
+// }
+
+ db->zone_count--;
+
+ //return KNOT_EOK;
+ return z;
+}
+
+/*----------------------------------------------------------------------------*/
+
+//knot_zone_t *knot_zonedb_replace_zone(knot_zonedb_t *db,
+// knot_zone_t *zone)
+//{
+// knot_zone_t *z = knot_zonedb_find_zone(db,
+// knot_node_owner(knot_zone_apex(zone)));
+// if (z == NULL) {
+// return NULL;
+// }
+
+// /*! \todo The replace should be atomic!!! */
+
+// dbg_zonedb("Found zone: %p\n", z);
+
+// int ret = skip_remove(db->zones,
+// (void *)knot_node_owner(knot_zone_apex(zone)),
+// NULL, NULL);
+// if (ret != 0) {
+// return NULL;
+// }
+
+// dbg_zonedb("Removed zone, return value: %d\n", ret);
+// dbg_zonedb("Old zone: %p\n", z);
+
+// ret = skip_insert(db->zones,
+// (void *)knot_node_owner(knot_zone_apex(zone)),
+// (void *)zone, NULL);
+
+// dbg_zonedb("Inserted zone, return value: %d\n", ret);
+
+// if (ret != 0) {
+// // return the removed zone back
+// skip_insert(db->zones,
+// (void *)knot_node_owner(knot_zone_apex(z)),
+// (void *)z, NULL);
+// /*! \todo There may be problems and the zone may remain
+// removed. */
+// return NULL;
+// }
+
+// return z;
+//}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_t *knot_zonedb_find_zone(const knot_zonedb_t *db,
+ const knot_dname_t *zone_name)
+{
+ knot_zone_t dummy_zone;
+ dummy_zone.name = (knot_dname_t *)zone_name;
+ return (knot_zone_t *)gen_tree_find(db->zone_tree, &dummy_zone);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_zone_t *knot_zonedb_find_zone_for_name(knot_zonedb_t *db,
+ const knot_dname_t *dname)
+{
+ if (db == NULL || dname == NULL) {
+ return NULL;
+ }
+
+ knot_zone_t dummy_zone;
+ dummy_zone.name = (knot_dname_t *)dname;
+ void *found = NULL;
+ int exact_match = gen_tree_find_less_or_equal(db->zone_tree,
+ &dummy_zone,
+ &found);
+ UNUSED(exact_match);
+
+ knot_zone_t *zone = (found) ? (knot_zone_t *)found : NULL;
+
+dbg_zonedb_exec(
+ char *name = knot_dname_to_str(dname);
+ dbg_zonedb("Found zone for name %s: %p\n", name, zone);
+ free(name);
+);
+ if (zone != NULL && zone->contents != NULL
+ && knot_dname_compare(zone->contents->apex->owner, dname) != 0
+ && !knot_dname_is_subdomain(dname, zone->contents->apex->owner)) {
+ zone = NULL;
+ }
+
+ return zone;
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zone_contents_t *knot_zonedb_expire_zone(knot_zonedb_t *db,
+ const knot_dname_t *zone_name)
+{
+ if (db == NULL || zone_name == NULL) {
+ return NULL;
+ }
+
+ // Remove the contents from the zone, but keep the zone in the zonedb.
+
+ knot_zone_t *zone = knot_zonedb_find_zone(db, zone_name);
+ if (zone == NULL) {
+ return NULL;
+ }
+
+ return knot_zone_switch_contents(zone, NULL);
+}
+
+/*----------------------------------------------------------------------------*/
+
+knot_zonedb_t *knot_zonedb_copy(const knot_zonedb_t *db)
+{
+ knot_zonedb_t *db_new =
+ (knot_zonedb_t *)malloc(sizeof(knot_zonedb_t));
+ CHECK_ALLOC_LOG(db_new, NULL);
+
+ db_new->zone_tree = gen_tree_shallow_copy(db->zone_tree);
+ if (db_new->zone_tree == NULL) {
+ free(db_new);
+ return NULL;
+ }
+
+ return db_new;
+}
+
+size_t knot_zonedb_zone_count(const knot_zonedb_t *db)
+{
+ return db->zone_count;
+}
+
+struct knot_zone_db_tree_arg {
+ const knot_zone_t **zones;
+ size_t count;
+};
+
+static void save_zone_to_array(void *node, void *data)
+{
+ knot_zone_t *zone = (knot_zone_t *)node;
+ struct knot_zone_db_tree_arg *args =
+ (struct knot_zone_db_tree_arg *)data;
+ assert(data);
+ args->zones[args->count++] = zone;
+}
+
+const knot_zone_t **knot_zonedb_zones(const knot_zonedb_t *db)
+{
+ struct knot_zone_db_tree_arg args;
+ args.zones = malloc(sizeof(knot_zone_t) * db->zone_count);
+ args.count = 0;
+ CHECK_ALLOC_LOG(args.zones, NULL);
+
+ gen_tree_apply_inorder(db->zone_tree, save_zone_to_array,
+ &args);
+ assert(db->zone_count == args.count);
+
+ return args.zones;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void knot_zonedb_free(knot_zonedb_t **db)
+{
+ gen_tree_destroy(&((*db)->zone_tree), NULL ,NULL);
+ free(*db);
+ *db = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void delete_zone_from_db(void *node, void *data)
+{
+ UNUSED(data);
+ knot_zone_t *zone = (knot_zone_t *)node;
+ assert(zone);
+ synchronize_rcu();
+ knot_zone_deep_free(&zone, 0);
+}
+
+void knot_zonedb_deep_free(knot_zonedb_t **db)
+{
+ dbg_zonedb("Deleting zone db (%p).\n", *db);
+// dbg_zonedb("Is it empty (%p)? %s\n",
+// (*db)->zones, skip_is_empty((*db)->zones) ? "yes" : "no");
+
+//dbg_zonedb_exec(
+// int i = 1;
+// char *name = NULL;
+// while (zn != NULL) {
+// dbg_zonedb("%d. zone: %p, key: %p\n", i, zn->value,
+// zn->key);
+// assert(zn->key == ((knot_zone_t *)zn->value)->apex->owner);
+// name = knot_dname_to_str((knot_dname_t *)zn->key);
+// dbg_zonedb(" zone name: %s\n", name);
+// free(name);
+
+// zn = skip_next(zn);
+// }
+
+// zn = skip_first((*db)->zones);
+//);
+
+// while (zn != NULL) {
+// zone = (knot_zone_t *)zn->value;
+// assert(zone != NULL);
+
+// // remove the zone from the database
+// skip_remove((*db)->zones, zn->key, NULL, NULL);
+// // wait for all readers to finish
+// synchronize_rcu;
+// // destroy the zone
+// knot_zone_deep_free(&zone, 0);
+
+// zn = skip_first((*db)->zones);
+// }
+
+// assert(skip_is_empty((*db)->zones));
+
+// skip_destroy_list(&(*db)->zones, NULL, NULL);
+ gen_tree_destroy(&((*db)->zone_tree), delete_zone_from_db, NULL);
+ assert((*db)->zone_tree == NULL);
+ free(*db);
+ *db = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
diff --git a/src/libknot/zone/zonedb.h b/src/libknot/zone/zonedb.h
new file mode 100644
index 0000000..d5a4992
--- /dev/null
+++ b/src/libknot/zone/zonedb.h
@@ -0,0 +1,145 @@
+/*!
+ * \file zonedb.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * \brief Zone database structure and API for manipulating it.
+ *
+ * Zone database groups several zones and provides functions for finding
+ * suitable zone for a domain name, for searching in a particular zone, etc.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOT_ZONEDB_H_
+#define _KNOT_ZONEDB_H_
+
+#include "common/general-tree.h"
+#include "zone/zone.h"
+#include "zone/node.h"
+#include "dname.h"
+
+/*!
+ * \brief Zone database structure. Contains all zones managed by the server.
+ */
+struct knot_zonedb {
+ general_tree_t *zone_tree; /*!< AVL tree of zones. */
+ size_t zone_count;
+};
+
+typedef struct knot_zonedb knot_zonedb_t;
+
+/*----------------------------------------------------------------------------*/
+
+/*!
+ * \brief Allocates and initializes the zone database structure.
+ *
+ * \return Pointer to the created zone database structure or NULL if an error
+ * occured.
+ */
+knot_zonedb_t *knot_zonedb_new();
+
+/*!
+ * \brief Adds new zone to the database.
+ *
+ * \param db Zone database to store the zone.
+ * \param zone Parsed zone.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_EZONEIN
+ */
+int knot_zonedb_add_zone(knot_zonedb_t *db, knot_zone_t *zone);
+
+/*!
+ * \brief Removes the given zone from the database if it exists.
+ *
+ * \note Assumes that the zone was adjusted using knot_zone_adjust_dnames().
+ * If it was not, it may leak some memory due to checks used in
+ * knot_rdata_deep_free().
+ *
+ * \param db Zone database to remove from.
+ * \param zone_name Name of the zone to be removed.
+ * \param destroy_zone Set to <> 0 if you do want the function to destroy the
+ * zone after removing from zone database. Set to 0
+ * otherwise.
+ *
+ * \retval KNOT_EOK
+ * \retval KNOT_ENOZONE
+ */
+knot_zone_t * knot_zonedb_remove_zone(knot_zonedb_t *db,
+ const knot_dname_t *zone_name);
+
+//knot_zone_t *knot_zonedb_replace_zone(knot_zonedb_t *db,
+// knot_zone_t *zone);
+
+/*!
+ * \brief Finds zone exactly matching the given zone name.
+ *
+ * \param db Zone database to search in.
+ * \param zone_name Domain name representing the zone name.
+ *
+ * \return Zone with \a zone_name being the owner of the zone apex or NULL if
+ * not found.
+ */
+knot_zone_t *knot_zonedb_find_zone(const knot_zonedb_t *db,
+ const knot_dname_t *zone_name);
+
+
+/*!
+ * \brief Finds zone the given domain name should belong to.
+ *
+ * \param db Zone database to search in.
+ * \param dname Domain name to find zone for.
+ *
+ * \retval Zone in which the domain name should be present or NULL if no such
+ * zone is found.
+ */
+const knot_zone_t *knot_zonedb_find_zone_for_name(knot_zonedb_t *db,
+ const knot_dname_t *dname);
+
+knot_zone_contents_t *knot_zonedb_expire_zone(knot_zonedb_t *db,
+ const knot_dname_t *zone_name);
+
+size_t knot_zonedb_zone_count(const knot_zonedb_t *db);
+const knot_zone_t **knot_zonedb_zones(const knot_zonedb_t *db);
+
+/*!
+ * \brief Destroys and deallocates the zone database structure (but not the
+ * zones within).
+ *
+ * \param db Zone database to be destroyed.
+ */
+void knot_zonedb_free(knot_zonedb_t **db);
+
+/*!
+ * \brief Destroys and deallocates the whole zone database including the zones.
+ *
+ * \note Assumes that the zone was adjusted using knot_zone_adjust_dnames().
+ * If it was not, it may leak some memory due to checks used in
+ * knot_rdata_deep_free().
+ *
+ * \param db Zone database to be destroyed.
+ */
+void knot_zonedb_deep_free(knot_zonedb_t **db);
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* _KNOT_ZONEDB_H_ */
+
+/*! @} */
diff --git a/src/tests/README b/src/tests/README
new file mode 100644
index 0000000..2f299ad
--- /dev/null
+++ b/src/tests/README
@@ -0,0 +1,10 @@
+Unit testing
+------------
+
+Make assembles "unittest" binary with all of the planned tests included.
+So far it is accepting the same parameters as the "cutedns",
+but an own parameter format is being developed.
+
+Example:
+bin/unittest samples/example.com.zone
+
diff --git a/src/tests/common/acl_tests.c b/src/tests/common/acl_tests.c
new file mode 100644
index 0000000..b4232ac
--- /dev/null
+++ b/src/tests/common/acl_tests.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/socket.h>
+
+#include "tests/common/acl_tests.h"
+#include "common/sockaddr.h"
+#include "common/acl.h"
+
+static int acl_tests_count(int argc, char *argv[]);
+static int acl_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api acl_tests_api = {
+ "ACL", //! Unit name
+ &acl_tests_count, //! Count scheduled tests
+ &acl_tests_run //! Run scheduled tests
+};
+
+static int acl_tests_count(int argc, char *argv[])
+{
+ return 13;
+}
+
+static int acl_tests_run(int argc, char *argv[])
+{
+ // 1. Create an ACL
+ acl_t *acl = acl_new(ACL_DENY, "simple ACL");
+ ok(acl != 0, "acl: new");
+
+ // 2. Create IPv4 address
+ sockaddr_t test_v4;
+ int ret = sockaddr_set(&test_v4, AF_INET, "127.0.0.1", 12345);
+ ok(ret > 0, "acl: new IPv4 address");
+
+ // 3. Create IPv6 address
+ sockaddr_t test_v6;
+ ret = sockaddr_set(&test_v6, AF_INET6, "::1", 54321);
+ ok(ret > 0, "acl: new IPv6 address");
+
+ // 4. Create simple IPv4 rule
+ ret = acl_create(acl, &test_v4, ACL_ACCEPT);
+ ok(ret == ACL_ACCEPT, "acl: inserted IPv4 rule");
+
+ // 5. Create simple IPv6 rule
+ ret = acl_create(acl, &test_v6, ACL_ACCEPT);
+ ok(ret == ACL_ACCEPT, "acl: inserted IPv6 rule");
+
+ // 6. Create simple IPv4 'any port' rule
+ sockaddr_t test_v4a;
+ sockaddr_set(&test_v4a, AF_INET, "20.20.20.20", 0);
+ ret = acl_create(acl, &test_v4a, ACL_ACCEPT);
+ ok(ret == ACL_ACCEPT, "acl: inserted IPv4 'any port' rule");
+
+ // 7. Attempt to match unmatching address
+ sockaddr_t unmatch_v4;
+ sockaddr_set(&unmatch_v4, AF_INET, "10.10.10.10", 24424);
+ ret = acl_match(acl, &unmatch_v4);
+ ok(ret == ACL_DENY, "acl: matching non-existing address");
+
+ // 8. Attempt to match unmatching IPv6 address
+ sockaddr_t unmatch_v6;
+ sockaddr_set(&unmatch_v6, AF_INET6, "2001:db8::1428:57ab", 24424);
+ ret = acl_match(acl, &unmatch_v6);
+ ok(ret == ACL_DENY, "acl: matching non-existing IPv6 address");
+
+ // 9. Attempt to match matching address
+ ret = acl_match(acl, &test_v4);
+ ok(ret == ACL_ACCEPT, "acl: matching existing address");
+
+ // 10. Attempt to match matching address
+ ret = acl_match(acl, &test_v6);
+ ok(ret == ACL_ACCEPT, "acl: matching existing IPv6 address");
+
+ // 11. Attempt to match matching 'any port' address
+ sockaddr_t match_v4a;
+ sockaddr_set(&match_v4a, AF_INET, "20.20.20.20", 24424);
+ ret = acl_match(acl, &match_v4a);
+ ok(ret == ACL_ACCEPT, "acl: matching existing IPv4 'any port' address");
+
+ // 12. Attempt to match matching address without matching port
+ sockaddr_set(&unmatch_v4, AF_INET, "127.0.0.1", 54321);
+ ret = acl_match(acl, &unmatch_v4);
+ ok(ret == ACL_DENY, "acl: matching address without matching port");
+
+ // 13. Invalid parameters
+ lives_ok({
+ acl_delete(0);
+ acl_create(0, 0, ACL_ERROR);
+ acl_match(0, 0);
+ acl_truncate(0);
+ acl_name(0);
+ }, "acl: won't crash with NULL parameters");
+
+ // Return
+ return 0;
+}
diff --git a/src/tests/common/acl_tests.h b/src/tests/common/acl_tests.h
new file mode 100644
index 0000000..a928e2d
--- /dev/null
+++ b/src/tests/common/acl_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_ACL_TESTS_H_
+#define _KNOTD_ACL_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api acl_tests_api;
+
+#endif /* _KNOTD_ACL_TESTS_H_ */
diff --git a/src/tests/common/da_tests.c b/src/tests/common/da_tests.c
new file mode 100644
index 0000000..627e8aa
--- /dev/null
+++ b/src/tests/common/da_tests.c
@@ -0,0 +1,330 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tests/common/da_tests.h"
+#include "common/dynamic-array.h"
+#include <unistd.h>
+#include <urcu.h>
+
+static int da_tests_count(int argc, char *argv[]);
+static int da_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api da_tests_api = {
+ "Dynamic array",
+ &da_tests_count,
+ &da_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+
+static const int DA_TEST_COUNT = 5;
+static const int RCU_THREADS = 3;
+static const int DA_FRAGMENT = 10;
+static const int DA_DEF_SIZE = 1000;
+static const int DA_OPERATIONS = 1000;
+enum Operations {
+ DA_RESERVE = 0,
+ DA_OCCUPY = 1,
+ DA_RELEASE = 2,
+ DA_OPCOUNT = 3
+};
+
+static int da_tests_count(int argc, char *argv[])
+{
+ return DA_TEST_COUNT;
+}
+
+static void do_something(int loops)
+{
+ int i;
+ int res = 1;
+
+ static const int LOOPS = 10000;
+
+ for (int j = 1; j <= LOOPS; ++j) {
+ for (i = 1; i <= loops; ++i) {
+ res *= i;
+ }
+ }
+}
+
+static void *test_rcu_routine(void *obj)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+
+ do_something(1000);
+
+ rcu_read_unlock();
+ rcu_unregister_thread();
+
+ return NULL;
+}
+
+static int test_rcu_threads()
+{
+ // Create threads
+ pthread_t *threads = malloc(RCU_THREADS * sizeof(pthread_t));
+ for (int i = 0; i < RCU_THREADS; ++i) {
+ if (pthread_create(&threads[i], NULL, test_rcu_routine, NULL)) {
+ diag("rcu: failed to create thread %d", i);
+ free(threads);
+ return 0;
+ }
+ }
+
+ // Join threads
+ void *pret = NULL;
+ for (int i = 0; i < RCU_THREADS; ++i) {
+ if (pthread_join(threads[i], &pret)) {
+ diag("rcu: failed to join thread %d", i);
+ free(threads);
+ return 0;
+ }
+ }
+
+ synchronize_rcu();
+ free(threads);
+
+ return 1;
+}
+
+static int test_da_init(da_array_t *arr)
+{
+ return da_initialize(arr, DA_DEF_SIZE, sizeof(uint)) == 0;
+}
+
+static int test_da_random_op(da_array_t *arr)
+{
+ unsigned seed = (unsigned)time(0);
+ uint allocated = DA_DEF_SIZE;
+ uint size = 0;
+
+ for (int i = 0; i < DA_OPERATIONS; ++i) {
+ int r = rand_r(&seed) % DA_OPCOUNT;
+ int count = rand_r(&seed) % DA_FRAGMENT + 1;
+
+ switch (r) {
+
+ // Perform reserve operation
+ case DA_RESERVE:
+ if (da_reserve(arr, count) >= 0 &&
+ size <= allocated) {
+ if ((allocated - size) < count) {
+ allocated *= 2;
+ }
+ } else {
+ diag("dynamic-array: da_reserve(%p, %d) failed"
+ " (size %d, alloc'd %d)",
+ arr, count, size, allocated);
+ return 0;
+ }
+ break;
+
+ // Perform occupy operation
+ case DA_OCCUPY:
+ if (da_occupy(arr, count) == 0) {
+ uint *items = (uint *) da_get_items(arr);
+ for (int j = 0; j < da_get_count(arr); ++j) {
+ items[j] = rand_r(&seed);
+ }
+ if (size <= allocated &&
+ (allocated - size) >= count) {
+ size += count;
+ } else {
+ return 0;
+ }
+ } else {
+ diag("dynamic-array: da_occupy(%p, %d) failed"
+ " (size %d, alloc'd %d)",
+ arr, count, size, allocated);
+ return 0;
+ }
+ break;
+
+ // Perform release operation
+ case DA_RELEASE:
+ if (arr->count > 0) {
+ count = (rand_r(&seed) % DA_FRAGMENT) % arr->count;
+ da_release(arr, count);
+
+ if (size <= allocated && size >= count) {
+ size -= count;
+ } else {
+ return 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Check allocated / size
+ if (allocated != arr->allocated || size != arr->count) {
+ diag("dynamic-array: allocated memory %d (expected %d)"
+ " size %d (expected %d) mismatch",
+ arr->allocated, allocated, arr->count, size);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void *test_da_read(void *obj)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+
+ unsigned seed = (unsigned)time(0);
+ da_array_t *arr = (da_array_t *) obj;
+ int index = rand_r(&seed) % da_get_count(arr);
+
+ note(" dynamic-array: read thread");
+ note(" read thread: saving pointer to %d. item", index);
+ uint *item = &((uint *) da_get_items(arr))[index];
+ note(" read thread: before: pointer: %p item: %u", item, *item);
+
+ do_something(100000);
+
+ note(" read thread after: pointer: %p item: %u", item, *item);
+ rcu_read_unlock();
+ note(" read thread unlocked: pointer: %p item: %u", item, *item);
+
+ do_something(10000);
+
+ note(" read thread: now the item should be deallocated");
+ //note(" read thread: pointer: %p item: %u", item, *item);
+
+ rcu_unregister_thread();
+
+ return NULL;
+}
+
+static int test_da_resize_holding(da_array_t *arr)
+{
+ int ret = 1;
+ rcu_register_thread();
+ pthread_t reader;
+
+ // Create thread for reading
+ note("dynamic-array: creating read threads");
+ if (pthread_create(&reader, NULL, test_da_read, (void *)arr)) {
+ diag("dynamic-array: failed to create reading thread",
+ __func__);
+ rcu_unregister_thread();
+ return 0;
+ }
+
+ // Wait some time, so the other thread gets the item for reading
+ do_something(5000);
+
+ // Force resize
+ note(" dynamic-array: array resized");
+ if (da_reserve(arr, arr->allocated - arr->count + 1) == -1) {
+ diag("dynamic-array: da_reserve(%p, %d) failed", arr,
+ arr->allocated - arr->count + 1);
+ ret = 0;
+ }
+
+ //Wait for the thread to finish
+ void *pret = NULL;
+ if (pthread_join(reader, &pret)) {
+ diag("dynamic-array: failed to join reading thread",
+ __func__);
+ ret = 0;
+ }
+
+ rcu_unregister_thread();
+ return ret;
+}
+
+static int test_da_resize(da_array_t *arr)
+{
+ unsigned seed = (unsigned)time(0);
+ int orig_count = da_get_count(arr);
+ note("dynamic-array: allocated: %d, items: %d", arr->allocated,
+ orig_count);
+ // store the items currently in the array
+ int *items = (int *)malloc(orig_count * sizeof(int));
+ for (int i = 0; i < orig_count; ++i) {
+ items[i] = ((int *)da_get_items(arr))[i];
+ }
+
+ // force resize
+ int res = 0;
+ while ((res = da_reserve(arr, 10)) == 0) {
+ int i = da_get_count(arr);
+ da_occupy(arr, 10);
+ for (; i < da_get_count(arr); ++i) {
+ ((int *)da_get_items(arr))[i] = rand_r(&seed);
+ }
+ }
+
+ if (res < 0) {
+ diag("dynamic-array: failed to reserve space");
+ return 0;
+ }
+
+ int errors = 0;
+ for (int i = 0; i < orig_count; ++i) {
+ if (items[i] != ((int *)da_get_items(arr))[i]) {
+ diag("dynamic-array: Wrong item on position %d."
+ "Should be: %d, "
+ "present value: %d", i, items[i],
+ ((int *)da_get_items(arr))[i]);
+ ++errors;
+ }
+ }
+
+ free(items);
+
+ return errors == 0;
+}
+
+static int da_tests_run(int argc, char *argv[])
+{
+ // Init
+ rcu_init();
+ da_array_t array;
+
+ // Test 1: test rcu
+ ok(test_rcu_threads(), "dynamic-array: rcu tests");
+
+ // Test 2: init
+ ok(test_da_init(&array), "dynamic-array: init");
+
+ // Test 3: reserve/occupy random operations
+ ok(test_da_random_op(&array),
+ "dynamic-array: randomized reserve/occupy/release");
+
+ // Test 4: resizing array while holding an item
+ ok(test_da_resize_holding(&array),
+ "dynamic-array: resize array while holding an item");
+
+ // Test 5: resize
+ ok(test_da_resize(&array), "dynamic-array: resize array");
+
+ // Cleanup
+ da_destroy(&array);
+ return 0;
+}
diff --git a/src/tests/common/da_tests.h b/src/tests/common/da_tests.h
new file mode 100644
index 0000000..d51b7be
--- /dev/null
+++ b/src/tests/common/da_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_DA_TESTS_H_
+#define _KNOTD_DA_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api da_tests_api;
+
+#endif /* _KNOTD_DA_TESTS_H_ */
diff --git a/src/tests/common/events_tests.c b/src/tests/common/events_tests.c
new file mode 100644
index 0000000..d7702fe
--- /dev/null
+++ b/src/tests/common/events_tests.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "tests/common/events_tests.h"
+#include "common/evqueue.h"
+#include "common/evsched.h"
+
+static int events_tests_count(int argc, char *argv[]);
+static int events_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api events_tests_api = {
+ "Event queue and scheduler", //! Unit name
+ &events_tests_count, //! Count scheduled tests
+ &events_tests_run //! Run scheduled tests
+};
+
+void* term_thr(void *arg)
+{
+ evsched_t *s = (evsched_t *)arg;
+
+ /* Sleep for 100ms. */
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000; // 100ms
+ select(0, 0, 0, 0, &tv);
+
+ /* Issue termination event. */
+ evsched_schedule_term(s, 0);
+ return 0;
+}
+
+static int events_tests_count(int argc, char *argv[])
+{
+ return 9 + 11;
+}
+
+static int events_tests_run(int argc, char *argv[])
+{
+ /*
+ * Event queue tests.
+ */
+
+ // 1. Construct an event queue
+ evqueue_t *q = evqueue_new();
+ ok(q != 0, "evqueue: new");
+
+ // 2. Send integer through event queue
+ int ret = 0;
+ uint8_t sent = 0xaf, rcvd = 0;
+ ret = evqueue_write(q, &sent, sizeof(uint8_t));
+ ok(ret == sizeof(uint8_t), "evqueue: send byte through");
+
+ // 3. Receive byte from event queue
+ ret = evqueue_read(q, &rcvd, sizeof(uint8_t));
+ ok(ret == sizeof(uint8_t), "evqueue: received byte");
+
+ // 4. Received match
+ ok(sent == rcvd, "evqueue: received byte match");
+
+ // 5. Sending event
+ event_t ev, rev;
+ memset(&ev, 0, sizeof(event_t));
+ memset(&rev, 0, sizeof(event_t));
+ ev.type = 0xfa11;
+ ev.data = (void*)0xceed;
+ ret = evqueue_add(q, &ev);
+ ok(ret == 0, "evqueue: sent event to queue");
+
+ // 6. Poll for new events
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100 * 1000 * 1000; // 100ms
+ ret = evqueue_poll(q, &ts, 0);
+ ok(ret > 0, "evqueue: polling queue for events");
+
+ // 7. Compare received event
+ ret = evqueue_get(q, &rev);
+ /* Compare useful data, as event owner was changed in evqueue_get(). */
+ if (ev.type == rev.type && ev.data == rev.data) {
+ ret = 0;
+ }
+ ok(ret == 0, "evqueue: received event matches sent");
+
+ // 8. Invalid parameters
+ lives_ok({
+ evqueue_free(0);
+ evqueue_poll(0,0,0);
+ evqueue_read(0, 0, 0);
+ evqueue_write(0, 0, 0);
+ evqueue_read(0, 0, 0);
+ evqueue_get(0, 0);
+ evqueue_add(0, 0);
+ }, "evqueue: won't crash with NULL parameters");
+
+ // 9. Free event queue
+ lives_ok({evqueue_free(&q);}, "evqueue: delete");
+
+ /*
+ * Event scheduler tests.
+ */
+
+ // 1. Construct event scheduler
+ event_t *e = 0;
+ evsched_t *s = evsched_new();
+ ok(s != 0, "evsched: new");
+
+ // 2. Schedule event to happen after N ms
+ int msecs = 50;
+ struct timeval st, rt;
+ gettimeofday(&st, 0);
+ e = evsched_schedule_cb(s, 0, (void*)0xcafe, msecs);
+ ok(e != 0, "evsched: scheduled empty event after %dms", msecs);
+
+ // 3. Wait for next event
+ e = evsched_next(s);
+ evsched_event_finished(s);
+ gettimeofday(&rt, 0);
+ ok(e != 0, "evsched: received valid event");
+
+ // 4. Check receive time
+ double passed = (rt.tv_sec - st.tv_sec) * 1000;
+ passed += (rt.tv_usec - st.tv_usec) / 1000;
+ double margin = msecs * 0.2;
+ double lb = msecs - margin, ub = msecs + margin;
+ int in_bounds = (passed >= lb) && (passed <= ub);
+ ok(in_bounds, "evsched: receive time %.1lfms is in <%.1lf,%.1lf>",
+ passed, lb, ub);
+
+ // 5. Check data
+ ok(e->data == (void*)0xcafe, "evsched: received data is valid");
+
+ // 6. Delete event
+ lives_ok({evsched_event_free(s, e);}, "evsched: deleted event");
+
+ // 7. Insert and immediately cancel an event
+ e = evsched_schedule_cb(s, 0, (void*)0xdead, 1000);
+ ret = evsched_cancel(s, e);
+ ok(ret == 0, "evsched: inserted and cancelled an event");
+ if (e) {
+ evsched_event_free(s, e);
+ }
+
+ // 8. Start listener thread and block
+ pthread_t t;
+ pthread_create(&t, 0, term_thr, s);
+ e = evsched_next(s);
+ evsched_event_finished(s);
+ ok(e != 0, "evsched: received termination event");
+
+ // 9. Termination event is valid
+ ok(e->type == EVSCHED_TERM, "evsched: termination event is valid");
+ evsched_event_free(s, e);
+ pthread_join(t, 0);
+
+ // 10. Invalid parameters
+ lives_ok({
+ evsched_delete(0);
+ evsched_event_new(0, 0);
+ evsched_event_free(0, 0);
+ evsched_next(0);
+ evsched_schedule(0, 0, 0);
+ evsched_schedule_cb(0, 0, 0, 0);
+ evsched_schedule_term(0, 0);
+ evsched_cancel(0, 0);
+
+ }, "evsched: won't crash with NULL parameters");
+
+ // 11. Delete event scheduler
+ lives_ok({evsched_delete(&s);}, "evsched: delete");
+
+
+ return 0;
+}
diff --git a/src/tests/common/events_tests.h b/src/tests/common/events_tests.h
new file mode 100644
index 0000000..b54b6da
--- /dev/null
+++ b/src/tests/common/events_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD__EVENTS_TESTS_H_
+#define _KNOTD__EVENTS_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api events_tests_api;
+
+#endif /* _KNOTD__EVENTS_TESTS_H_ */
diff --git a/src/tests/common/fdset_tests.c b/src/tests/common/fdset_tests.c
new file mode 100644
index 0000000..7dd95a1
--- /dev/null
+++ b/src/tests/common/fdset_tests.c
@@ -0,0 +1,177 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+#include "tests/common/fdset_tests.h"
+#include "common/fdset.h"
+
+#define WRITE_PATTERN ((char) 0xde)
+#define WRITE_PATTERN_LEN sizeof(char)
+
+
+/* Subtract the `struct timeval' values X and Y,
+ storing the result in RESULT.
+ Return 1 if the difference is negative, otherwise 0.
+ Copyright http://www.delorie.com/gnu/docs/glibc/libc_428.html
+*/
+static int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval* y)
+{
+ /* Perform the carry for the later subtraction by updating y. */
+ if (x->tv_usec < y->tv_usec) {
+ int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+ y->tv_usec -= 1000000 * nsec;
+ y->tv_sec += nsec;
+ }
+ if (x->tv_usec - y->tv_usec > 1000000) {
+ int nsec = (x->tv_usec - y->tv_usec) / 1000000;
+ y->tv_usec += 1000000 * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ tv_usec is certainly positive. */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
+
+static size_t timeval_diff(struct timeval *from, struct timeval *to) {
+ struct timeval res;
+ timeval_subtract(&res, to, from);
+ return res.tv_sec*1000 + res.tv_usec/1000;
+}
+
+static int fdset_tests_count(int argc, char *argv[]);
+static int fdset_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api fdset_tests_api = {
+ "Native fdset poll wrapper", //! Unit name
+ &fdset_tests_count, //! Count scheduled tests
+ &fdset_tests_run //! Run scheduled tests
+};
+
+void* thr_action(void *arg)
+{
+ int *fd = (int *)arg;
+
+ /* Sleep for 100ms. */
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000; // 100ms
+ select(0, 0, 0, 0, &tv);
+
+ /* Write pattern. */
+ char pattern = WRITE_PATTERN;
+ int ret = write(*fd, &pattern, WRITE_PATTERN_LEN);
+ ret = ret; /* Use variable. */
+
+ return 0;
+}
+
+static int fdset_tests_count(int argc, char *argv[])
+{
+ return 11;
+}
+
+static int fdset_tests_run(int argc, char *argv[])
+{
+ diag("fdset: implements '%s'", fdset_method());
+
+ /* 1. Create fdset. */
+ fdset_t *set = fdset_new();
+ ok(set != 0, "fdset: new");
+
+ /* 2. Create pipe. */
+ int fds[2], tmpfds[2];
+ int ret = pipe(fds);
+ ok(ret >= 0, "fdset: pipe() works");
+ ret = pipe(tmpfds);
+
+ /* 3. Add fd to set. */
+ ret = fdset_add(set, fds[0], OS_EV_READ);
+ ok(ret == 0, "fdset: add to set works");
+ fdset_add(set, tmpfds[0], OS_EV_READ);
+
+ /* Schedule write. */
+ struct timeval ts, te;
+ gettimeofday(&ts, 0);
+ pthread_t t;
+ pthread_create(&t, 0, thr_action, &fds[1]);
+
+ /* 4. Watch fdset. */
+ ret = fdset_wait(set);
+ gettimeofday(&te, 0);
+ size_t diff = timeval_diff(&ts, &te);
+
+ ok(ret > 0 && diff > 99 && diff < 10000,
+ "fdset: poll returned events in %zu ms", diff);
+
+ /* 5. Prepare event set. */
+ fdset_it_t it;
+ ret = fdset_begin(set, &it);
+ ok(ret == 0 && it.fd == fds[0], "fdset: begin is valid, ret=%d", ret);
+
+ /* 6. Receive data. */
+ char buf = 0x00;
+ ret = read(it.fd, &buf, WRITE_PATTERN_LEN);
+ ok(ret >= 0 && buf == WRITE_PATTERN, "fdset: contains valid data, fd=%d", it.fd);
+
+ /* 7. Iterate event set. */
+ ret = fdset_next(set, &it);
+ ok(ret < 0, "fdset: boundary check works");
+
+ /* 8. Remove from event set. */
+ ret = fdset_remove(set, fds[0]);
+ ok(ret == 0, "fdset: remove from fdset works");
+ close(fds[0]);
+ close(fds[1]);
+ ret = fdset_remove(set, tmpfds[0]);
+ close(tmpfds[1]);
+ close(tmpfds[1]);
+
+ /* 9. Poll empty fdset. */
+ ret = fdset_wait(set);
+ ok(ret <= 0, "fdset: polling empty fdset returns -1 (ret=%d)", ret);
+
+ /* 10. Crash test. */
+ lives_ok({
+ fdset_destroy(0);
+ fdset_add(0, -1, 0);
+ fdset_remove(0, -1);
+ fdset_wait(0);
+ fdset_begin(0, 0);
+ fdset_end(0, 0);
+ fdset_next(0, 0);
+ fdset_method();
+ }, "fdset: crash test successful");
+
+ /* 11. Destroy fdset. */
+ ret = fdset_destroy(set);
+ ok(ret == 0, "fdset: destroyed");
+
+ /* Cleanup. */
+ pthread_join(t, 0);
+
+ return 0;
+}
diff --git a/src/tests/common/fdset_tests.h b/src/tests/common/fdset_tests.h
new file mode 100644
index 0000000..d29e1a9
--- /dev/null
+++ b/src/tests/common/fdset_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_FDSET_TESTS_H_
+#define _KNOTD_FDSET_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api fdset_tests_api;
+
+#endif /* _KNOTD_FDSET_TESTS_H_ */
diff --git a/src/tests/common/skiplist_tests.c b/src/tests/common/skiplist_tests.c
new file mode 100644
index 0000000..4fe99ec
--- /dev/null
+++ b/src/tests/common/skiplist_tests.c
@@ -0,0 +1,198 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+
+#include "tests/common/skiplist_tests.h"
+#include "common/skip-list.h"
+
+static int skiplist_tests_count(int argc, char *argv[]);
+static int skiplist_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api skiplist_tests_api = {
+ "Skip list",
+ &skiplist_tests_count,
+ &skiplist_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+
+static const int SKIPLIST_TEST_COUNT = 5;
+
+static int skiplist_tests_count(int argc, char *argv[])
+{
+ return SKIPLIST_TEST_COUNT;
+}
+
+/* Comparing and merging limited to int keys used in test.
+ */
+int test_skip_compare_keys(void *key1, void *key2)
+{
+ return ((long)key1 < (long)key2) ?
+ -1 : (((long)key1 > (long)key2) ? 1 : 0);
+}
+
+int test_skip_merge_values(void **lvalue, void **rvalue)
+{
+ (*lvalue) = (void *)((long)(*lvalue) + (long)(*rvalue));
+ return 0;
+}
+
+int test_skiplist_create(skip_list_t **list)
+{
+ *list = skip_create_list(test_skip_compare_keys);
+ return *list != NULL;
+}
+
+int test_skiplist_fill(skip_list_t *list, long *uitems, int loops)
+{
+ int uitem_count = 0;
+ for (int i = 0; i < loops; ++i) {
+ long key = rand() % 100 + 1;
+ long value = rand() % 100 + 1;
+ int res = skip_insert(list, (void *)key, (void *)value,
+ test_skip_merge_values);
+ switch (res) {
+ case -2:
+ diag("skiplist: merging failed");
+ return 0;
+ break;
+ case -1:
+ diag("skiplist: insert failed");
+ return 0;
+ break;
+ case 0:
+ uitems[uitem_count++] = key;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return uitem_count;
+}
+
+int test_skiplist_lookup_seq(skip_list_t *list, long *uitems, int uitems_count)
+{
+ int errors = 0;
+
+ // Sequential lookup
+ for (int i = 0; i < uitems_count; ++i) {
+ void *found = skip_find(list, (void *) uitems[i]);
+ if (found == NULL) {
+ diag("skiplist: sequential "
+ "lookup failed, key: %d", uitems[i]);
+ ++errors;
+ }
+ }
+
+ if (errors) {
+ diag("skiplist: sequential lookup: %d found %d missed,"
+ " %.2f%% success rate",
+ uitems_count - errors, errors,
+ (uitems_count - errors) / (float) uitems_count * 100.0);
+ }
+
+ return errors == 0;
+}
+
+int test_skiplist_lookup_rand(skip_list_t *list, long *uitems, int uitems_count)
+{
+ int errors = 0;
+ srand((unsigned)time(NULL));
+
+ // Random lookup
+ for (int i = 0; i < uitems_count; ++i) {
+ long key = rand() % uitems_count + 1;
+ void *found = skip_find(list, (void *) key);
+ if (found == NULL) {
+ diag("skiplist: random lookup"
+ "failed, key: %d", uitems[i]);
+ ++errors;
+ }
+ }
+
+ if (errors) {
+ diag("skiplist: sequential lookup: "
+ "%d found %d missed, %.2f%% success rate",
+ uitems_count - errors, errors,
+ (uitems_count - errors) / (float) uitems_count * 100.0);
+ }
+ return errors == 0;
+}
+
+
+int test_skiplist_remove(skip_list_t *list, long *uitems, int uitems_count)
+{
+ int errors = 0;
+
+ // delete items
+ for (int i = 0; i < uitems_count; ++i) {
+ int res = skip_remove(list, (void *) uitems[i], NULL, NULL);
+ switch (res) {
+ case 0:
+ break;
+ default:
+ ++errors;
+ break;
+ }
+ }
+
+ if (errors) {
+ diag("skiplist: sequential lookup: %d found %d missed, "
+ "%.2f%% success rate",
+ uitems_count - errors, errors,
+ (uitems_count - errors) / (float) uitems_count * 100.0);
+ }
+ return errors == 0;
+}
+
+static int skiplist_tests_run(int argc, char *argv[])
+{
+ const int loops = 100;
+ int uitems_count = 0;
+ long *uitems = malloc(loops * sizeof(long));
+ skip_list_t *list = 0;
+
+ // Test 1: create
+ ok(test_skiplist_create(&list), "skiplist: create");
+
+ // Test 2: fill
+ ok(uitems_count = test_skiplist_fill(list, uitems, loops),
+ "skiplist: fill");
+
+ // Test 3: sequential lookup
+ ok(test_skiplist_lookup_seq(list, uitems, uitems_count),
+ "skiplist: sequential lookup");
+
+ // Test 4: sequential lookup
+ ok(test_skiplist_lookup_seq(list, uitems, uitems_count),
+ "skiplist: random lookup lookup");
+
+ // Test 5: remove items
+ ok(test_skiplist_remove(list, uitems, uitems_count),
+ "skiplist: random lookup lookup");
+
+ // Cleanup
+ skip_destroy_list(&list, NULL, NULL);
+ free(uitems);
+ return 0;
+}
diff --git a/src/tests/common/skiplist_tests.h b/src/tests/common/skiplist_tests.h
new file mode 100644
index 0000000..ff91706
--- /dev/null
+++ b/src/tests/common/skiplist_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_SKIPLIST_TESTS_H_
+#define _KNOTD_SKIPLIST_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api skiplist_tests_api;
+
+#endif /* _KNOTD_SKIPLIST_TESTS_H_ */
diff --git a/src/tests/common/slab_tests.c b/src/tests/common/slab_tests.c
new file mode 100644
index 0000000..f362ca0
--- /dev/null
+++ b/src/tests/common/slab_tests.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdbool.h>
+
+#include "tests/common/slab_tests.h"
+#include "common/slab/slab.h"
+#include "knot/common.h"
+
+/* Explicitly ask for symbols,
+ * as the constructor and destructor
+ * aren't created for test modules.
+ */
+extern void slab_init();
+extern void slab_deinit();
+
+static int slab_tests_count(int argc, char *argv[]);
+static int slab_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api slab_tests_api = {
+ "SLAB allocator", //! Unit name
+ &slab_tests_count, //! Count scheduled tests
+ &slab_tests_run //! Run scheduled tests
+};
+
+static int slab_tests_count(int argc, char *argv[])
+{
+ return 7;
+}
+
+static int slab_tests_run(int argc, char *argv[])
+{
+ // 1. Create slab cache
+ srand(time(0));
+ const unsigned pattern = 0xdeadbeef;
+ slab_cache_t cache;
+ int ret = slab_cache_init(&cache, sizeof(int));
+ ok(ret == 0, "slab: created empty cache");
+
+ // 2. Couple alloc/free
+ bool valid_free = true;
+ lives_ok({
+ for(int i = 0; i < 100; ++i) {
+ int* data = (int*)slab_cache_alloc(&cache);
+ *data = pattern;
+ slab_free(data);
+ if (*data == pattern)
+ valid_free = false;
+ }
+ }, "slab: couple alloc/free");
+
+ // 5. Verify freed block
+ ok(valid_free, "slab: freed memory is correctly invalidated");
+
+ // 4. Reap memory
+ slab_t* slab = cache.slabs_free;
+ int free_count = 0;
+ while (slab) {
+ slab_t* next = slab->next;
+ if (slab_isempty(slab)) {
+ ++free_count;
+ }
+ slab = next;
+ }
+
+ int reaped = slab_cache_reap(&cache);
+ cmp_ok(reaped, "==", free_count, "slab: cache reaping works");
+
+ // Stress cache
+ int alloc_count = 73521;
+ void** ptrs = alloca(alloc_count * sizeof(void*));
+ int ptrs_i = 0;
+ for(int i = 0; i < alloc_count; ++i) {
+ double roll = rand() / (double) RAND_MAX;
+ if ((ptrs_i == 0) || (roll < 0.6)) {
+ int id = ptrs_i++;
+ ptrs[id] = slab_cache_alloc(&cache);
+ if (ptrs[id] == 0) {
+ ptrs_i--;
+ } else {
+ int* data = (int*)ptrs[id];
+ *data = pattern;
+ }
+ } else {
+ slab_free(ptrs[--ptrs_i]);
+ }
+ }
+
+ // 5. Delete cache
+ slab_cache_destroy(&cache);
+ ok(cache.bufsize == 0, "slab: freed cache");
+
+ // 6. Greate GP allocator
+ slab_alloc_t alloc;
+ ret = slab_alloc_init(&alloc);
+ ok(ret == 0, "slab: created GP allocator");
+
+ // 7. Stress allocator
+ unsigned ncount = 0;
+ ptrs_i = 0;
+ for(int i = 0; i < alloc_count; ++i) {
+ double roll = rand() / (double) RAND_MAX;
+ size_t bsize = roll * 2048;
+ bsize = MAX(bsize, 8);
+ if ((ptrs_i == 0) || (roll < 0.6)) {
+ void* m = slab_alloc_alloc(&alloc, bsize);
+ if (m == 0) {
+ ++ncount;
+ } else {
+ ptrs[ptrs_i++] = m;
+ }
+ } else {
+ slab_free(ptrs[--ptrs_i]);
+ }
+ }
+
+ cmp_ok(ncount, "==", 0, "slab: GP allocator alloc/free working");
+
+ // 7. Destroy allocator
+ slab_alloc_destroy(&alloc);
+
+ return 0;
+}
diff --git a/src/tests/common/slab_tests.h b/src/tests/common/slab_tests.h
new file mode 100644
index 0000000..4d45fb8
--- /dev/null
+++ b/src/tests/common/slab_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_SLAB_TESTS_H_
+#define _KNOTD_SLAB_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api slab_tests_api;
+
+#endif /* _KNOTD_SLAB_TESTS_H_ */
diff --git a/src/tests/files/sample_conf b/src/tests/files/sample_conf
new file mode 100644
index 0000000..6cd9e50
--- /dev/null
+++ b/src/tests/files/sample_conf
@@ -0,0 +1,59 @@
+# configuration file will follow bird (and juniper) type of configuration file
+# i.e. curly brackets will be used;
+
+# what to do with };
+# a) ignore ; if it follows }
+
+system {
+
+ identity "I have no mouth and must scream";
+ version "Infinitesimal";
+ storage "/var/run/knot/";
+}
+
+keys {
+ key0.example.net hmac-md5 "Wg=="; # key special for one remote
+ key1.example.net hmac-md5 "==gW"; # implicit key for whole zone
+}
+
+remotes {
+ remote0 { address 1.2.3.4; }
+}
+
+zones {
+ example.net {
+ file "/var/lib/knot/example.net";
+ xfr-out remote0;
+ }
+}
+
+interfaces {
+ interface0 {
+ address 10.10.1.1;
+ port 53531;
+ }
+
+ interface1 {
+ address ::0;
+ # port 53;
+ }
+}
+
+log {
+ syslog {
+ any notice, warning, error;
+ zone all;
+ }
+
+ file "/var/log/knot/server.err" {
+ server error;
+ }
+
+ stderr {
+ any warning, error;
+ }
+
+ stdout {
+ any info;
+ }
+}
diff --git a/src/tests/knot/conf_tests.c b/src/tests/knot/conf_tests.c
new file mode 100644
index 0000000..61520ea
--- /dev/null
+++ b/src/tests/knot/conf_tests.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include "tests/knot/conf_tests.h"
+#include "knot/conf/conf.h"
+
+/* Resources. */
+#include "tests/sample_conf.rc"
+
+static int conf_tests_count(int argc, char *argv[]);
+static int conf_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api conf_tests_api = {
+ "Configuration parser", //! Unit name
+ &conf_tests_count, //! Count scheduled tests
+ &conf_tests_run //! Run scheduled tests
+};
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int conf_tests_count(int argc, char *argv[])
+{
+ return 21;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int conf_tests_run(int argc, char *argv[])
+{
+
+ // Test 1: Allocate new config
+ const char *config_fn = "rc:/sample_conf";
+ conf_t *conf = conf_new(config_fn);
+ ok(conf != 0, "config_new()");
+
+ // Test 2: Parse config
+ int ret = conf_parse_str(conf, sample_conf_rc);
+ ok(ret == 0, "parsing configuration file %s", config_fn);
+ skip(ret != 0, conf_tests_count(argc, argv) - 2);
+ {
+
+ // Test 3: Test server version (0-level depth)
+ is(conf->version, "Infinitesimal", "server version loaded ok");
+
+ // Test 4: Test interfaces (1-level depth)
+ ok(!EMPTY_LIST(conf->ifaces), "configured interfaces exist");
+
+ // Test 5,6,7,8: Interfaces content (2-level depth)
+ struct node *n = HEAD(conf->ifaces);
+ conf_iface_t *iface = (conf_iface_t*)n;
+ is(iface->address, "10.10.1.1", "interface0 address check");
+ cmp_ok(iface->port, "==", 53531, "interface0 port check");
+ n = n->next;
+ iface = (conf_iface_t*)n;
+ is(iface->address, "::0", "interface1 address check");
+ cmp_ok(iface->port, "==", 53, "interface1 default port check");
+
+ // Test 9,10: Check server key
+ if(conf->key_count <= 0) {
+ ok(0, "TSIG key algorithm check - NO KEY FOUND");
+ ok(0, "TSIG key secret check - NO KEY FOUND");
+ } else {
+ knot_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k;
+ cmp_ok(k->algorithm, "==", KNOT_TSIG_ALG_HMAC_MD5,
+ "TSIG key algorithm check");
+ is(k->secret, "Wg==", "TSIG key secret check");
+ }
+
+ // Test 11,12,13,14,15,16,17,18: Check logging facilities
+ cmp_ok(conf->logs_count, "==", 4, "log facilites count check");
+ n = HEAD(conf->logs);
+ ok(!EMPTY_LIST(conf->logs), "log facilities not empty");
+
+ conf_log_t *log = (conf_log_t*)n;
+ node *nm = HEAD(log->map);
+ conf_log_map_t *m = (conf_log_map_t*)nm;
+ cmp_ok(log->type, "==", LOGT_SYSLOG, "log0 is syslog");
+
+ skip(EMPTY_LIST(log->map), 5);
+ {
+ cmp_ok(m->source, "==", LOG_ANY, "syslog first rule is ANY");
+ int mask = LOG_MASK(LOG_NOTICE)|LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR);
+ cmp_ok(m->prios, "==", mask, "syslog mask is equal");
+ nm = nm->next;
+ m = (conf_log_map_t*)nm;
+ ok(m != 0, "syslog has more than 1 rule");
+ skip(!m, 2);
+ {
+ cmp_ok(m->source, "==", LOG_ZONE, "syslog next rule is for zone");
+ cmp_ok(m->prios, "==", 0xff, "rule for zone is: any level");
+ }
+ endskip;
+ } endskip;
+
+ // Test 19,20: File facility checks
+ n = n->next;
+ log = (conf_log_t*)n;
+ ok(n != 0, "log has next facility");
+ skip(!n, 1);
+ {
+ is(log->file, "/var/log/knot/server.err", "log file matches");
+ } endskip;
+
+ // Test 21: Load key dname
+ const char *sample_str = "key0.example.net";
+ knot_dname_t *sample = knot_dname_new_from_str(sample_str,
+ strlen(sample_str), 0);
+ if (conf->key_count > 0) {
+ knot_key_t *k = &((conf_key_t *)HEAD(conf->keys))->k;
+ ok(knot_dname_compare(sample, k->name) == 0,
+ "TSIG key dname check");
+ } else {
+ ok(0, "TSIG key dname check - NO KEY FOUND");
+ }
+ knot_dname_free(&sample);
+
+ } endskip;
+
+ // Deallocating config
+ conf_free(conf);
+
+ return 0;
+}
diff --git a/src/tests/knot/conf_tests.h b/src/tests/knot/conf_tests.h
new file mode 100644
index 0000000..dfd2fd7
--- /dev/null
+++ b/src/tests/knot/conf_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_CONF_TESTS_H_
+#define _KNOTD_CONF_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api conf_tests_api;
+
+#endif /* _KNOTD_CONF_TESTS_H_ */
diff --git a/src/tests/knot/dthreads_tests.c b/src/tests/knot/dthreads_tests.c
new file mode 100644
index 0000000..d95fbed
--- /dev/null
+++ b/src/tests/knot/dthreads_tests.c
@@ -0,0 +1,392 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <pthread.h>
+#include <sched.h>
+#include <sys/select.h>
+#include <signal.h>
+
+#include "tests/knot/dthreads_tests.h"
+#include "knot/server/dthreads.h"
+
+static int dt_tests_count(int argc, char *argv[]);
+static int dt_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api dthreads_tests_api = {
+ "DThreads",
+ &dt_tests_count,
+ &dt_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+static const int DT_TEST_COUNT = 23;
+
+/* Unit runnable data. */
+static pthread_mutex_t _runnable_mx;
+static volatile int _runnable_i = 0;
+static const int _runnable_cycles = 10000;
+
+/*! \brief Unit runnable. */
+int runnable(struct dthread_t *thread)
+{
+ for (int i = 0; i < _runnable_cycles; ++i) {
+
+ // Increase counter
+ pthread_mutex_lock(&_runnable_mx);
+ ++_runnable_i;
+ pthread_mutex_unlock(&_runnable_mx);
+
+ // Cancellation point
+ if (dt_is_cancelled(thread)) {
+ break;
+ }
+
+ // Yield
+ sched_yield();
+ }
+
+ return 0;
+}
+
+/*! \brief Unit blocking runnable. */
+int runnable_simio(struct dthread_t *thread)
+{
+ // Infinite blocking, must be interrupted
+ select(0, 0, 0, 0, 0);
+ return 0;
+}
+
+/*! \brief Create unit. */
+static inline dt_unit_t *dt_test_create(int size)
+{
+ return dt_create(size);
+}
+
+/*! \brief Assign a task. */
+static inline int dt_test_single(dt_unit_t *unit)
+{
+ return dt_repurpose(unit->threads[0], &runnable, NULL) == 0;
+}
+
+/*! \brief Assign task to all unit threads. */
+static inline int dt_test_coherent(dt_unit_t *unit)
+{
+ int ret = 0;
+ for (int i = 0; i < unit->size; ++i) {
+ ret += dt_repurpose(unit->threads[i], &runnable, NULL);
+ }
+
+ return ret == 0;
+}
+
+/*! \brief Repurpose single thread. */
+static inline int dt_test_repurpose(dt_unit_t *unit, int id)
+{
+ return dt_repurpose(unit->threads[id], &runnable_simio, NULL) == 0;
+}
+
+/*! \brief Cancel single thread. */
+static inline int dt_test_cancel(dt_unit_t *unit, int id)
+{
+ return dt_cancel(unit->threads[id]) == 0;
+}
+
+/*! \brief Reanimate dead threads. */
+static inline int dt_test_reanimate(dt_unit_t *unit)
+{
+ // Compact all threads
+ int ret = 0;
+ ret += dt_compact(unit);
+
+ // Remove purpose from all
+ for (int i = 0; i < unit->size; ++i) {
+ ret += dt_repurpose(unit->threads[i], 0, 0);
+ }
+
+ // Set single thread to purpose
+ ret += dt_repurpose(unit->threads[0], &runnable, 0);
+
+ // Restart
+ _runnable_i = 0;
+ ret += dt_start(unit);
+
+ // Wait for finish
+ ret += dt_join(unit);
+
+ // Verify
+ int expected = 1 * _runnable_cycles;
+ if (_runnable_i != expected) {
+ return 0;
+ }
+
+ // Check return codes
+ return ret == 0;
+}
+
+/*! \brief Resize unit. */
+static inline int dt_test_resize(dt_unit_t *unit, int size)
+{
+ // Resize
+ int ret = 0;
+ ret = dt_resize(unit, size);
+ if (ret < 0) {
+ return 0;
+ }
+
+ // Check outcome
+ if (unit->size != size) {
+ return 0;
+ }
+
+ // Repurpose all
+ _runnable_i = 0;
+ for (int i = 0; i < size; ++i) {
+ ret += dt_repurpose(unit->threads[i], &runnable, 0);
+ ret += dt_start_id(unit->threads[i]);
+ }
+
+ // Wait for finish
+ ret += dt_join(unit);
+
+ // Verify
+ int expected = size * _runnable_cycles;
+ note("resize test: %d threads, %d ticks, %d expected",
+ size, _runnable_i, expected);
+ if (_runnable_i != expected) {
+ return 0;
+ }
+
+ // Check return codes
+ return ret == 0;
+}
+
+/*! \brief Resize unit while threads are active. */
+static inline int dt_test_liveresize(dt_unit_t *unit)
+{
+ // Size
+ int size = unit->size;
+ int size_hi = size + 2;
+ int size_lo = size - 1;
+
+ // Expand
+ int ret = 0;
+ ret = dt_resize(unit, size_hi);
+ if (ret < 0) {
+ return 0;
+ }
+
+ // Repurpose all
+ for (int i = 0; i < unit->size; ++i) {
+ ret += dt_repurpose(unit->threads[i], &runnable, 0);
+ }
+
+ // Restart
+ _runnable_i = 0;
+ ret += dt_start(unit);
+
+ // Shrink
+ ret += dt_resize(unit, size_lo);
+
+ // Wait for finish
+ ret += dt_join(unit);
+
+ // Verify
+ int expected_hi = size_hi * _runnable_cycles;
+ int expected_lo = size_lo * _runnable_cycles;
+ note("resize test: %d->%d->%d threads, %d ticks, <%d,%d> expected",
+ size, size_hi, size_lo, _runnable_i, expected_lo, expected_hi);
+
+ if (_runnable_i > expected_hi || _runnable_i < expected_lo) {
+ return 0;
+ }
+
+ // Check return codes
+ return ret == 0;
+}
+
+/*! \brief Start unit. */
+static inline int dt_test_start(dt_unit_t *unit)
+{
+ return dt_start(unit) == 0;
+}
+
+/*! \brief Stop unit. */
+static inline int dt_test_stop(dt_unit_t *unit)
+{
+ return dt_stop(unit);
+}
+
+/*! \brief Join unit. */
+static inline int dt_test_join(dt_unit_t *unit)
+{
+ return dt_join(unit) == 0;
+}
+
+/*! API: return number of tests. */
+static int dt_tests_count(int argc, char *argv[])
+{
+ return DT_TEST_COUNT;
+}
+
+// Signal handler
+static void interrupt_handle(int s)
+{
+}
+
+/*! API: run tests. */
+static int dt_tests_run(int argc, char *argv[])
+{
+ // Register service and signal handler
+ struct sigaction sa;
+ sa.sa_handler = interrupt_handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, NULL); // Interrupt
+
+ /* Initialize */
+ srand(time(NULL));
+ struct timeval tv;
+ pthread_mutex_init(&_runnable_mx, NULL);
+
+ /* Test 1: Create unit */
+ dt_unit_t *unit = dt_test_create(dt_optimal_size());
+ ok(unit != 0, "dthreads: create unit (optimal size %d)", unit->size);
+ skip(unit == 0, DT_TEST_COUNT - 1);
+
+ /* Test 2: Assign a single task. */
+ ok(dt_test_single(unit), "dthreads: assign single task");
+
+ /* Test 3: Start tasks. */
+ _runnable_i = 0;
+ ok(dt_test_start(unit), "dthreads: start single task");
+
+ /* Test 4: Wait for tasks. */
+ ok(dt_test_join(unit), "dthreads: join threads");
+
+ /* Test 5: Compare counter. */
+ int expected = _runnable_cycles * 1;
+ cmp_ok(_runnable_i, "==", expected, "dthreads: result ok");
+
+ /* Test 6: Repurpose threads. */
+ _runnable_i = 0;
+ ok(dt_test_coherent(unit), "dthreads: repurpose to coherent");
+
+ /* Test 7: Restart threads. */
+ ok(dt_test_start(unit), "dthreads: start coherent unit");
+
+ /* Test 8: Repurpose single thread. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 4000 + rand() % 1000; // 4-5ms
+ note("waiting for %dus to let thread do some work ...",
+ tv.tv_usec);
+ select(0, 0, 0, 0, &tv);
+ ok(dt_test_repurpose(unit, 0), "dthreads: repurpose on-the-fly");
+
+ /* Test 9: Cancel blocking thread. */
+ tv.tv_sec = 0;
+ tv.tv_usec = (250 + rand() % 500) * 1000; // 250-750ms
+ note("waiting for %dms to let thread pretend blocking I/O ...",
+ tv.tv_usec / 1000);
+ select(0, 0, 0, 0, &tv);
+ ok(dt_test_cancel(unit, 0), "dthreads: cancel blocking thread");
+
+ /* Test 10: Wait for tasks. */
+ ok(dt_test_join(unit), "dthreads: join threads");
+
+ /* Test 11: Compare counter. */
+ int expected_lo = _runnable_cycles * (unit->size - 1);
+ cmp_ok(_runnable_i, ">=", expected_lo,
+ "dthreads: result %d is => %d", _runnable_i, expected_lo);
+
+ /* Test 12: Compare counter #2. */
+ int expected_hi = _runnable_cycles * unit->size;
+ cmp_ok(_runnable_i, "<=", expected_hi,
+ "dthreads: result %d is <= %d", _runnable_i, expected_hi);
+
+ /* Test 13: Reanimate dead threads. */
+ ok(dt_test_reanimate(unit), "dthreads: reanimate dead threads");
+
+ /* Test 14: Expand unit by 100%. */
+ int size = unit->size * 2;
+ ok(dt_test_resize(unit, size),
+ "dthreads: expanding unit to size * 2 (%d threads)", size);
+
+ /* Test 15: Shrink unit to half. */
+ size = unit->size / 2;
+ ok(dt_test_resize(unit, size),
+ "dthreads: shrinking unit to size / 2 (%d threads)", size);
+
+ /* Test 16: Resize while threads are active. */
+ ok(dt_test_liveresize(unit), "dthreads: resizing unit while active");
+
+ /* Test 17: Deinitialize */
+ dt_delete(&unit);
+ ok(unit == 0, "dthreads: delete unit");
+ endskip;
+
+ /* Test 18: Wrong values. */
+ unit = dt_create(-1);
+ ok(unit == 0, "dthreads: create with negative count");
+ unit = dt_create_coherent(dt_optimal_size(), 0, 0);
+
+ /* Test 19: NULL runnable. */
+ cmp_ok(dt_start(unit), "==", 0, "dthreads: start with NULL runnable");
+
+ /* Test 20: resize to negative value. */
+ cmp_ok(dt_resize(unit, -19),
+ "<", 0, "dthreads: resize to negative size");
+
+ /* Test 21: resize to zero value. */
+ cmp_ok(dt_resize(unit, 0), "<", 0, "dthreads: resize to NULL size");
+ dt_join(unit);
+ dt_delete(&unit);
+
+ /* Test 22: NULL operations crashing. */
+ int op_count = 14;
+ int expected_min = op_count * -1;
+ // All functions must return -1 at least
+ int ret = 0;
+ lives_ok( {
+ ret += dt_activate(0); // -1
+ ret += dt_cancel(0); // -1
+ ret += dt_compact(0); // -1
+ dt_delete(0); //
+ ret += dt_is_cancelled(0); // 0
+ ret += dt_join(0); // -1
+ ret += dt_repurpose(0, 0, 0); // -1
+ ret += dt_resize(0, 0); // -1
+ ret += dt_setprio(0, 0); // -1
+ ret += dt_signalize(0, SIGALRM); // -1
+ ret += dt_start(0); // -1
+ ret += dt_start_id(0); // -1
+ ret += dt_stop(0); // -1
+ ret += dt_stop_id(0); // -1
+ ret += dt_unit_lock(0); // -1
+ ret += dt_unit_unlock(0); // -1
+ }, "dthreads: not crashed while executing functions on NULL context");
+
+ /* Test 23: expected results. */
+ cmp_ok(ret, "<=", expected_min,
+ "dthreads: correct values when passed NULL context "
+ "(%d, min: %d)", ret, expected_min);
+
+ pthread_mutex_destroy(&_runnable_mx);
+ return 0;
+}
diff --git a/src/tests/knot/dthreads_tests.h b/src/tests/knot/dthreads_tests.h
new file mode 100644
index 0000000..e41bdc5
--- /dev/null
+++ b/src/tests/knot/dthreads_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_DTHREADS_TESTS_H_
+#define _KNOTD_DTHREADS_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api dthreads_tests_api;
+
+#endif /* _KNOTD_DTHREADS_TESTS_H_ */
diff --git a/src/tests/knot/journal_tests.c b/src/tests/knot/journal_tests.c
new file mode 100644
index 0000000..21c92fe
--- /dev/null
+++ b/src/tests/knot/journal_tests.c
@@ -0,0 +1,184 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <string.h>
+
+#include "tests/knot/journal_tests.h"
+#include "knot/server/journal.h"
+#include "knot/other/error.h"
+
+static int journal_tests_count(int argc, char *argv[]);
+static int journal_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api journal_tests_api = {
+ "Journal",
+ &journal_tests_count,
+ &journal_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+static const int JOURNAL_TEST_COUNT = 11;
+
+/*! \brief Generate random string with given length. */
+static int randstr(char* dst, size_t len)
+{
+ for (int i = 0; i < len - 1; ++i) {
+ dst[i] = '0' + (int) (('Z'-'0') * (rand() / (RAND_MAX + 1.0)));
+ }
+ dst[len - 1] = '\0';
+
+ return 0;
+}
+
+/*! \brief Walk journal of chars into buffer. */
+static int _wbi = 0;
+static char _walkbuf[7];
+static int walkchars_cmp(uint64_t k1, uint64_t k2) {
+ return k1 - k2;
+}
+
+static int walkchars(journal_t *j, journal_node_t *n) {
+ journal_read(j, n->id, walkchars_cmp, _walkbuf + _wbi);
+ ++_wbi;
+ return 0;
+}
+
+/*! API: return number of tests. */
+static int journal_tests_count(int argc, char *argv[])
+{
+ return JOURNAL_TEST_COUNT;
+}
+
+/*! API: run tests. */
+static int journal_tests_run(int argc, char *argv[])
+{
+ /* Test 1: Create tmpfile. */
+ int fsize = 8092;
+ int jsize = 6;
+ char jfn_buf[] = "/tmp/journal.XXXXXX";
+ int tmp_fd = mkstemp(jfn_buf);
+ ok(tmp_fd >= 0, "journal: create temporary file");
+ skip(tmp_fd < 0, JOURNAL_TEST_COUNT - 1);
+
+ /* Test 2: Create journal. */
+ const char *jfilename = jfn_buf;
+ int ret = journal_create(jfilename, jsize);
+ ok(ret == KNOTD_EOK, "journal: create journal '%s'", jfilename);
+
+ /* Test 3: Open journal. */
+ journal_t *j = journal_open(jfilename, fsize, 0);
+ ok(j != 0, "journal: open");
+
+ /* Test 4: Write entry to log. */
+ const char *sample = "deadbeef";
+ ret = journal_write(j, 0x0a, sample, strlen(sample));
+ ok(ret == KNOTD_EOK, "journal: write");
+
+ /* Test 5: Read entry from log. */
+ char tmpbuf[64] = {'\0'};
+ ret = journal_read(j, 0x0a, 0, tmpbuf);
+ ok(ret == KNOTD_EOK, "journal: read entry");
+
+ /* Test 6: Compare read data. */
+ ret = strncmp(sample, tmpbuf, strlen(sample));
+ ok(ret == 0, "journal: read data integrity check");
+
+ /* Append several characters. */
+ journal_write(j, 0, "X", 1); /* Dummy */
+ char word[7] = { 'w', 'o', 'r', 'd', '0', '\0', '\0' };
+ for (int i = 0; i < strlen(word); ++i) {
+ journal_write(j, i, word+i, 1);
+ }
+
+ /* Test 7: Compare journal_walk() result. */
+ _wbi = 0;
+ journal_walk(j, walkchars);
+ _walkbuf[_wbi] = '\0';
+ ret = strcmp(word, _walkbuf);
+ ok(ret == 0, "journal: read data integrity check 2 '%s'", _walkbuf);
+ _wbi = 0;
+
+ /* Test 8: Change single letter and compare. */
+ word[5] = 'X';
+ journal_write(j, 5, word+5, 1); /* append 'X', shifts out 'w' */
+ journal_walk(j, walkchars);
+ _walkbuf[_wbi] = '\0';
+ ret = strcmp(word + 1, _walkbuf);
+ ok(ret == 0, "journal: read data integrity check 3 '%s'", _walkbuf);
+ _wbi = 0;
+
+ /* Close journal. */
+ journal_close(j);
+
+ /* Recreate journal. */
+ remove(jfilename);
+ fsize = 8092;
+ jsize = 512;
+ ret = journal_create(jfilename, jsize);
+ j = journal_open(jfilename, fsize, 0);
+
+ /* Test 9: Write random data. */
+ int chk_key = 0;
+ char chk_buf[64] = {'\0'};
+ ret = 0;
+ const int itcount = 1;//jsize * 5 + 5;
+ for (int i = 0; i < itcount; ++i) {
+ int key = rand() % 65535;
+ randstr(tmpbuf, sizeof(tmpbuf));
+ if (journal_write(j, key, tmpbuf, sizeof(tmpbuf)) != KNOTD_EOK) {
+ ret = -1;
+ break;
+ }
+
+ /* Store some key on the end. */
+ if (i == itcount - 2) {
+ chk_key = key;
+ memcpy(chk_buf, tmpbuf, sizeof(chk_buf));
+ }
+ }
+ ok(ret == 0, "journal: sustained looped writes");
+
+ /* Test 10: Check data integrity. */
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ journal_read(j, chk_key, 0, tmpbuf);
+ ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf));
+ ok(ret == 0, "journal: read data integrity check");
+
+ /* Test 11: Reopen log and re-read value. */
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ journal_close(j);
+ j = journal_open(jfilename, fsize, 0);
+ journal_read(j, chk_key, 0, tmpbuf);
+ ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf));
+ ok(ret == 0, "journal: read data integrity check after close/open");
+
+ /* Close journal. */
+ journal_close(j);
+
+ /* Close temporary file fd. */
+ close(tmp_fd);
+
+ /* Delete journal. */
+ remove(jfilename);
+
+ endskip;
+
+ return 0;
+}
diff --git a/src/tests/knot/journal_tests.h b/src/tests/knot/journal_tests.h
new file mode 100644
index 0000000..beec8ca
--- /dev/null
+++ b/src/tests/knot/journal_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_JOURNAL_TESTS_H_
+#define _KNOTD_JOURNAL_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api journal_tests_api;
+
+#endif /* _KNOTD_JOURNAL_TESTS_H_ */
diff --git a/src/tests/knot/server_tests.c b/src/tests/knot/server_tests.c
new file mode 100644
index 0000000..5ae04d8
--- /dev/null
+++ b/src/tests/knot/server_tests.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "tests/knot/server_tests.h"
+#include "knot/server/server.h"
+
+static int server_tests_count(int argc, char *argv[]);
+static int server_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api server_tests_api = {
+ "Server",
+ &server_tests_count,
+ &server_tests_run
+};
+
+/*
+ * Unit implementation.
+ */
+
+static const int SERVER_TEST_COUNT = 4;
+
+/*! Test: create server. */
+server_t *test_server_create()
+{
+ return server_create();
+}
+
+/*! Test: start server. */
+int test_server_start(server_t *s)
+{
+ return server_start(s) == 0;
+}
+
+/*! Test: finish server. */
+int test_server_finish(server_t *s)
+{
+ return server_wait(s) == 0;
+}
+
+/*! Test: stop server. */
+int test_server_destroy(server_t *s)
+{
+ server_destroy(&s);
+ return s == 0;
+}
+
+/*! API: return number of tests. */
+static int server_tests_count(int argc, char *argv[])
+{
+ return SERVER_TEST_COUNT + 1;
+}
+
+// Signal handler
+static void interrupt_handle(int s)
+{
+}
+
+/*! API: run tests. */
+static int server_tests_run(int argc, char *argv[])
+{
+ server_t *server = 0;
+ int ret = 0;
+
+ // Register service and signal handler
+ struct sigaction sa;
+ sa.sa_handler = interrupt_handle;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, NULL); // Interrupt
+
+ //! Test server for correct initialization
+ server = test_server_create();
+ ok(server != 0, "server: initialized");
+
+ //! Test server startup
+ ret = 0;
+ lives_ok( {
+ ret = test_server_start(server);
+ }, "server: not crashing on runtime");
+
+ //! Test server exit code
+ ok(ret, "server: started ok");
+ if (ret) {
+ server_stop(server);
+ } else {
+ diag("server crashed, skipping deinit and destroy tests");
+ }
+
+ //! Test server waiting for finish
+ skip(!ret, 2);
+ ok(test_server_finish(server), "server: waiting for finish");
+
+ //! Test server for correct deinitialization
+ ok(test_server_destroy(server), "server: deinit");
+ endskip;
+
+ return 0;
+}
diff --git a/src/tests/knot/server_tests.h b/src/tests/knot/server_tests.h
new file mode 100644
index 0000000..43ad0c1
--- /dev/null
+++ b/src/tests/knot/server_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_SERVER_TESTS_H_
+#define _KNOTD_SERVER_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api server_tests_api;
+
+#endif /* _KNOTD_SERVER_TESTS_H_ */
diff --git a/src/tests/libknot/files/parsed_data b/src/tests/libknot/files/parsed_data
new file mode 100644
index 0000000..4027c92
--- /dev/null
+++ b/src/tests/libknot/files/parsed_data
Binary files differ
diff --git a/src/tests/libknot/files/parsed_data_queries b/src/tests/libknot/files/parsed_data_queries
new file mode 100644
index 0000000..5857c87
--- /dev/null
+++ b/src/tests/libknot/files/parsed_data_queries
Binary files differ
diff --git a/src/tests/libknot/files/raw_data b/src/tests/libknot/files/raw_data
new file mode 100644
index 0000000..f94236b
--- /dev/null
+++ b/src/tests/libknot/files/raw_data
Binary files differ
diff --git a/src/tests/libknot/files/raw_data_queries b/src/tests/libknot/files/raw_data_queries
new file mode 100644
index 0000000..9062d5a
--- /dev/null
+++ b/src/tests/libknot/files/raw_data_queries
Binary files differ
diff --git a/src/tests/libknot/libknot/cuckoo_tests.c b/src/tests/libknot/libknot/cuckoo_tests.c
new file mode 100644
index 0000000..c1306a3
--- /dev/null
+++ b/src/tests/libknot/libknot/cuckoo_tests.c
@@ -0,0 +1,382 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <time.h>
+#include <assert.h>
+
+#include "tests/libknot/libknot/cuckoo_tests.h"
+
+#include "libknot/hash/cuckoo-hash-table.h"
+
+//#define CK_TEST_DEBUG
+//#define CK_TEST_LOOKUP
+//#define CK_TEST_OUTPUT
+//#define CK_TEST_REMOVE
+//#define CK_TEST_COMPARE
+
+#ifdef CK_TEST_DEBUG
+#define CK_TEST_LOOKUP
+#define CK_TEST_OUTPUT
+#define CK_TEST_REMOVE
+#define CK_TEST_COMPARE
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+static int cuckoo_tests_count(int argc, char *argv[]);
+static int cuckoo_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api cuckoo_tests_api = {
+ "Cuckoo hashing", //! Unit name
+ &cuckoo_tests_count, //! Count scheduled tests
+ &cuckoo_tests_run //! Run scheduled tests
+};
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * Unit implementation
+ */
+static const int CUCKOO_TESTS_COUNT = 13;
+static const int CUCKOO_MAX_ITEMS = 1000;
+static const int CUCKOO_TEST_MAX_KEY_SIZE = 10;
+
+typedef struct test_cuckoo_items {
+ char **keys;
+ size_t *key_sizes;
+ size_t *values;
+ size_t *deleted;
+ int count;
+ int total_count;
+} test_cuckoo_items;
+
+/*----------------------------------------------------------------------------*/
+
+static inline char rand_char()
+{
+ return (char)((rand() % 26) + 97);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static inline void rand_str(char *str, int size)
+{
+ for (int i = 0; i < size; ++i) {
+ str[i] = rand_char();
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int cuckoo_tests_count(int argc, char *argv[])
+{
+ return CUCKOO_TESTS_COUNT;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_create(ck_hash_table_t **table, uint items)
+{
+ *table = ck_create_table(items);
+ return (*table != NULL);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_insert(ck_hash_table_t *table,
+ const test_cuckoo_items *items)
+{
+ assert(table != NULL);
+ int errors = 0;
+ for (int i = 0; i < items->count; ++i) {
+ assert(items->values[i] != 0);
+ if (ck_insert_item(table, items->keys[i], items->key_sizes[i],
+ (void *)items->values[i]) != 0) {
+ ++errors;
+ }
+ }
+ return errors == 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_lookup(ck_hash_table_t *table,
+ const test_cuckoo_items *items)
+{
+ int errors = 0;
+ for (int i = 0; i < items->count; ++i) {
+ const ck_hash_table_item_t *found = ck_find_item(
+ table, items->keys[i], items->key_sizes[i]);
+ if (!found) {
+ if (items->deleted[i] == 0) {
+ diag("Not found item with key %.*s\n",
+ items->key_sizes[i], items->keys[i]);
+ ++errors;
+ }
+ } else {
+ if (items->deleted[i] != 0
+ || found->key != items->keys[i]
+ || (size_t)(found->value) != items->values[i]) {
+ diag("Found item with key %.*s (size %u) "
+ "(should be %.*s (size %u)) and value %zu "
+ "(should be %d).\n",
+ found->key_length, found->key,
+ found->key_length, items->key_sizes[i],
+ items->keys[i], items->key_sizes[i],
+ (size_t)found->value, items->values[i]);
+ ++errors;
+ }
+ }
+ }
+
+ if (errors > 0) {
+ diag("Not found %d of %d items.\n", errors, items->count);
+ } else {
+ note("Found %d items.\n", items->count);
+ }
+
+ return errors == 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_delete(ck_hash_table_t *table, test_cuckoo_items *items)
+{
+ int errors = 0;
+ // delete approx. 1/10 items from the table
+ int count = rand() % (CUCKOO_MAX_ITEMS / 10) + 1;
+
+ for (int i = 0; i < count; ++i) {
+ int item = rand() % items->count;
+ if (items->deleted[item] == 0
+ && ck_delete_item(table, items->keys[item],
+ items->key_sizes[item], NULL, 0) != 0) {
+ ++errors;
+ } else {
+ items->deleted[item] = 1;
+ }
+ }
+
+ return errors == 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_modify(ck_hash_table_t *table, test_cuckoo_items *items)
+{
+ int errors = 0;
+ // modify approx. 1/10 items from the table
+ int count = rand() % (CUCKOO_MAX_ITEMS / 10) + 1;
+
+ for (int i = 0; i < count; ++i) {
+ int item = rand() % items->count;
+ int old_value = items->values[item];
+ items->values[item] = rand() + 1;
+ if (ck_update_item(table, items->keys[item],
+ items->key_sizes[item],
+ (void *)items->values[item], NULL) != 0
+ && items->deleted[item] == 1) {
+ ++errors;
+ items->values[item] = old_value;
+ }
+ }
+
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_rehash(ck_hash_table_t *table)
+{
+ return (ck_rehash(table) == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_resize(ck_hash_table_t *table)
+{
+ // test the resize explicitly
+ return (ck_resize_table(table) == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_cuckoo_full(ck_hash_table_t *table, test_cuckoo_items *items)
+{
+ // invoke the resize by inserting so much items that thay cannot
+ // fit into the table
+ int new_count = table->items;
+
+ while (new_count < hashsize(table->table_size_exp) * table->table_count) {
+ new_count += table->items;
+ }
+
+ note("Old item count: %d, new count: %d, capacity of the table: %d\n",
+ table->items, new_count,
+ hashsize(table->table_size_exp) * table->table_count);
+
+ assert(new_count <= items->total_count);
+
+ int errors = 0;
+
+ for (int i = items->count; i < new_count; ++i) {
+ assert(items->values[i] != 0);
+ if (ck_insert_item(table, items->keys[i], items->key_sizes[i],
+ (void *)items->values[i]) != 0) {
+ ++errors;
+ }
+ }
+
+ items->count = new_count;
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void create_random_items(test_cuckoo_items *items, int item_count)
+{
+ assert(items != NULL);
+
+ items->count = item_count;
+ items->total_count = item_count * 10;
+ items->values = (size_t *)malloc(items->total_count * sizeof(size_t));
+ items->key_sizes = (size_t *)malloc(items->total_count * sizeof(size_t));
+ items->deleted = (size_t *)malloc(items->total_count * sizeof(size_t));
+ items->keys = (char **)malloc(items->total_count * sizeof(char *));
+
+ for (int i = 0; i < items->total_count; ++i) {
+ int value = rand() + 1;
+ int key_size = rand() % CUCKOO_TEST_MAX_KEY_SIZE + 1;
+ char *key = malloc(key_size * sizeof(char));
+ assert(key != NULL);
+ rand_str(key, key_size);
+
+ // check if the key is not already in the table
+ int found = 0;
+ for (int j = 0; j < i; ++j) {
+ if (items->key_sizes[j] == key_size
+ && strncmp(items->keys[j], key, key_size) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ assert(value != 0);
+ items->values[i] = value;
+ items->key_sizes[i] = key_size;
+ items->keys[i] = key;
+ items->deleted[i] = 0;
+ } else {
+ free(key);
+ --i;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void delete_items(test_cuckoo_items *items)
+{
+ free(items->deleted);
+ free(items->key_sizes);
+ free(items->values);
+ for (int i = 0; i < items->total_count; ++i) {
+ free(items->keys[i]);
+ }
+ free(items->keys);
+}
+
+/*----------------------------------------------------------------------------*/
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int cuckoo_tests_run(int argc, char *argv[])
+{
+ srand(time(NULL));
+ int res;
+
+ const int item_count = rand() % CUCKOO_MAX_ITEMS + 1;
+ test_cuckoo_items *items = (test_cuckoo_items *)
+ malloc(sizeof(test_cuckoo_items));
+
+ ck_hash_table_t *table = NULL;
+
+ // Test 1: create
+ ok(res = test_cuckoo_create(&table, item_count),
+ "cuckoo hashing: create");
+
+ create_random_items(items, item_count);
+
+ skip(!res, 10);
+ // Test 2: insert
+ ok(test_cuckoo_insert(table, items), "cuckoo hashing: insert");
+
+ // Test 3: lookup
+ ok(test_cuckoo_lookup(table, items), "cuckoo hashing: lookup");
+
+ // Test 4: delete
+ ok(test_cuckoo_delete(table, items), "cuckoo hashing: delete");
+
+ // Test 5: lookup 2
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after delete");
+
+ // Test 6: modify
+ ok(test_cuckoo_modify(table, items), "cuckoo hashing: modify");
+
+ // Test 7: lookup 3
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after modify");
+
+ // Test 8: rehash
+ ok(test_cuckoo_rehash(table), "cuckoo hashing: rehash");
+
+ // Test 9: lookup 4
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after rehash");
+
+ // Test 10: resize
+ ok(test_cuckoo_resize(table), "cuckoo hashing: resize");
+
+ // Test 11: lookup 5
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after resize");
+
+ // Test 12: owerflow the table
+ ok(test_cuckoo_full(table, items), "cuckoo hashing: overflow");
+
+ // Test 13: lookup 5
+ ok(test_cuckoo_lookup(table, items),
+ "cuckoo hashing: lookup after overflow");
+
+ endskip;
+
+ /**
+ * \note These last 2 tests found some major bug in the cuckoo hash
+ * table, so running them results in abort upon assertion.
+ * Disabled for now.
+ */
+
+ // Cleanup
+ ck_destroy_table(&table, NULL, 0);
+ delete_items(items);
+ free(items);
+
+ return 0;
+}
diff --git a/src/tests/libknot/libknot/cuckoo_tests.h b/src/tests/libknot/libknot/cuckoo_tests.h
new file mode 100644
index 0000000..b6b0db8
--- /dev/null
+++ b/src/tests/libknot/libknot/cuckoo_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_CUCKOO_TESTS_H_
+#define _KNOTD_CUCKOO_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api cuckoo_tests_api;
+
+#endif /* _KNOTD_CUCKOO_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/dname_table_tests.c b/src/tests/libknot/libknot/dname_table_tests.c
new file mode 100644
index 0000000..0d00a44
--- /dev/null
+++ b/src/tests/libknot/libknot/dname_table_tests.c
@@ -0,0 +1,393 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+
+#include "dname_table_tests.h"
+#include "libknot/util/error.h"
+#include "libknot/zone/dname-table.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+
+static int knot_dname_table_tests_count(int argc, char *argv[]);
+static int knot_dname_table_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api dname_table_tests_api = {
+ "Dname table", //! Unit name
+ &knot_dname_table_tests_count, //! Count scheduled tests
+ &knot_dname_table_tests_run //! Run scheduled tests
+};
+
+/* Helper functions. */
+static knot_dname_t *dname_from_test_dname_str(const test_dname_t *test_dname)
+{
+ assert(test_dname != NULL);
+ knot_dname_t *ret = knot_dname_new_from_str (test_dname->str,
+ strlen(test_dname->str),
+ NULL);
+ CHECK_ALLOC(ret, NULL);
+
+ return ret;
+}
+
+static int dname_compare_sort_wrapper(const void *ptr1, const void *ptr2)
+{
+ const knot_dname_t *dname1 =
+ dname_from_test_dname_str((const test_dname_t *)ptr1);
+ const knot_dname_t *dname2 =
+ dname_from_test_dname_str((const test_dname_t *)ptr2);
+ assert(dname1 && dname2);
+ return knot_dname_compare(dname1, dname2);
+}
+
+/* Unit implementation. */
+enum {DNAME_TABLE_DNAME_COUNT = 3};
+
+/* Strings are enough, we're not testing dname here ... */
+static test_dname_t DNAME_TABLE_DNAMES[DNAME_TABLE_DNAME_COUNT] = {
+ /* list ptr, string, wire, length, labels, label_count */
+ {NULL, NULL, ".", NULL, 1, NULL, 0},
+ {NULL, NULL, "a.ns.nic.cz.", NULL, 13, NULL, 0},
+ {NULL, NULL, "b.ns.nic.cz.", NULL, 13, NULL, 0}
+};
+
+static int test_dname_table_new()
+{
+ knot_dname_table_t *table = knot_dname_table_new();
+ if (table == NULL) {
+ return 0;
+ }
+
+ knot_dname_table_free(&table);
+ return 1;
+}
+
+struct test_dname_table_arg {
+ /* Times two - safety measure. */
+ knot_dname_t *array[DNAME_TABLE_DNAME_COUNT * 2];
+ uint count;
+};
+
+static void save_dname_to_array(knot_dname_t *node, void *data)
+{
+ assert(data);
+ struct test_dname_table_arg *arg = (struct test_dname_table_arg *)data;
+ arg->array[arg->count] = node;
+ arg->count++;
+}
+
+static int test_dname_table_adding()
+{
+ int errors = 0;
+ knot_dname_table_t *table = knot_dname_table_new();
+ CHECK_ALLOC(table, 0);
+
+ /* Add NULL */
+ if (knot_dname_table_add_dname(table, NULL) != KNOT_EBADARG) {
+ diag("Adding NULL dname did not result in an error!");
+ errors++;
+ }
+
+ /* Add to NULL table*/
+ if (knot_dname_table_add_dname(NULL, NULL) != KNOT_EBADARG) {
+ diag("Adding to NULL table did not result in an error!");
+ errors++;
+ }
+
+ /* Add NULL */
+ if (knot_dname_table_add_dname_check(table, NULL) != KNOT_EBADARG) {
+ diag("Adding NULL dname did not result in an error!");
+ errors++;
+ }
+
+ /* Add to NULL table*/
+ if (knot_dname_table_add_dname_check(NULL, NULL) != KNOT_EBADARG) {
+ diag("Adding to NULL table did not result in an error!");
+ errors++;
+ }
+
+
+ /* Add valid dnames. */
+ for (int i = 0; i < DNAME_TABLE_DNAME_COUNT; i++) {
+ knot_dname_t *dname =
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]);
+ if (!dname) {
+ diag("Could not create dname from test dname!");
+ errors++;
+ continue;
+ }
+ if (knot_dname_table_add_dname(table, dname) != KNOT_EOK) {
+ diag("Could not add dname! (%s)",
+ DNAME_TABLE_DNAMES[i].str);
+ errors++;
+ }
+ }
+
+ /*
+ * Using inorder traversal of the table,
+ * create array containing dnames.
+ */
+
+ struct test_dname_table_arg arg;
+ arg.count = 0;
+
+ knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg);
+
+ if (arg.count != DNAME_TABLE_DNAME_COUNT) {
+ diag("Table contains too many dnames!");
+ /* No sense in continuing. */
+ knot_dname_table_deep_free(&table);
+ return 0;
+ }
+
+ /*
+ * Check that inordered array is really sorted
+ * and contains valid dnames.
+ */
+ for (int i = 0; i < DNAME_TABLE_DNAME_COUNT; i++) {
+ assert(arg.array[i]);
+ const char *str = knot_dname_to_str(arg.array[i]);
+ if (str == NULL) {
+ diag("Wrong dname in table!");
+ errors++;
+ continue;
+ }
+
+ if (arg.array[i]->size !=
+ DNAME_TABLE_DNAMES[i].size) {
+ diag("Wrong dname size in table!");
+ diag("Is: %u should be %u.",
+ arg.array[i]->size,
+ DNAME_TABLE_DNAMES[i].size);
+ errors++;
+ continue;
+ }
+
+ if (strncmp(str, DNAME_TABLE_DNAMES[i].str,
+ DNAME_TABLE_DNAMES[i].size) != 0) {
+ diag("Wrong dname wire in table!");
+ errors++;
+ }
+ }
+
+ /* Now add one dname once again. It has to be the first item! */
+
+ if (knot_dname_table_add_dname(table,
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0])) !=
+ KNOT_EOK) {
+ diag("Could not add dname to table once it's already there!");
+ /* Next test would not make sense. */
+ knot_dname_table_deep_free(&table);
+ return 0;
+ }
+
+ /*
+ * After walking the table, there should now be
+ * DNAME_TABLE_DNAME_COUNT + 1 items, with 2 identical
+ * items at the beginning.
+ */
+
+ memset(arg.array, 0,
+ sizeof(knot_dname_t *) * DNAME_TABLE_DNAME_COUNT * 2);
+ arg.count = 0;
+ knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg);
+
+ if (arg.count != DNAME_TABLE_DNAME_COUNT + 1) {
+ diag("Identical dname was not added!");
+ /* Again, next test would not make any sense. */
+ knot_dname_table_deep_free(&table);
+ return 0;
+ }
+
+ if (knot_dname_compare(arg.array[0], arg.array[1]) != 0) {
+ diag("First two dnames in table are not identical!");
+ errors++;
+ }
+
+ /* Delete table, wipe out array. */
+ knot_dname_table_deep_free(&table);
+ memset(arg.array, 0,
+ sizeof(knot_dname_t *) * DNAME_TABLE_DNAME_COUNT * 2);
+ arg.count = 0;
+
+ table = knot_dname_table_new();
+ assert(table);
+
+ /*
+ * Add dname with same content twice using knot_dname_table_add2 -
+ * table should now only contain one item.
+ */
+
+ knot_dname_t *tmp_dname =
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0]);
+ assert(tmp_dname);
+
+ if (knot_dname_table_add_dname_check(table, &tmp_dname) != KNOT_EOK) {
+ diag("Could not add dname using dname_table_add_dname2!");
+ knot_dname_table_deep_free(&table);
+ knot_dname_free(&tmp_dname);
+ return 0;
+ }
+
+ tmp_dname = dname_from_test_dname_str(&DNAME_TABLE_DNAMES[0]);
+ assert(tmp_dname);
+
+ knot_dname_t *dname_before_add = tmp_dname;
+
+ if (knot_dname_table_add_dname_check(table, &tmp_dname) != 1) {
+ diag("Could not add dname again using dname_table_add_dname2!");
+ knot_dname_table_deep_free(&table);
+ return 0;
+ }
+
+ if (tmp_dname == dname_before_add) {
+ diag("Dname was not freed after insertion!");
+ errors++;
+ }
+
+ knot_dname_table_tree_inorder_apply(table, save_dname_to_array, &arg);
+
+ if (arg.count != 1) {
+ diag("Add_dname2 has added dname when it shouldn't!");
+ errors++;
+ }
+
+ if (knot_dname_compare(tmp_dname, arg.array[0]) != 0) {
+ diag("Add_dname2 has added wrong dname!");
+ errors++;
+ }
+
+ knot_dname_table_deep_free(&table);
+ return (errors == 0);
+}
+
+static int test_dname_table_find()
+{
+ int errors = 0;
+ knot_dname_table_t *table = knot_dname_table_new();
+ assert(table);
+
+ if (knot_dname_table_find_dname(table, NULL) != NULL) {
+ diag("Dname table did not return NULL when searching NULL!");
+ errors++;
+ }
+
+ if (knot_dname_table_find_dname(NULL, NULL) != NULL) {
+ diag("Passing NULL instead of dname table did not "
+ "return NULL!");
+ errors++;
+ }
+
+ /* Add all dnames but the last one. */
+ for (int i = 0; i < DNAME_TABLE_DNAME_COUNT - 1; i++) {
+ knot_dname_t *dname =
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]);
+ if (!dname) {
+ diag("Could not create dname from test dname!");
+ errors++;
+ continue;
+ }
+ if (knot_dname_table_add_dname(table, dname) != KNOT_EOK) {
+ diag("Could not add dname! (%s)",
+ DNAME_TABLE_DNAMES[i].str);
+ errors++;
+ }
+ }
+
+ /* Search for added dnames. */
+ for (int i = 0; i < DNAME_TABLE_DNAME_COUNT - 1; i++) {
+ knot_dname_t *dname =
+ dname_from_test_dname_str(&DNAME_TABLE_DNAMES[i]);
+ if (!dname) {
+ diag("Could not create dname from test dname!");
+ errors++;
+ continue;
+ }
+
+ knot_dname_t *found_dname =
+ knot_dname_table_find_dname(table, dname);
+
+ if (found_dname == NULL) {
+ diag("Dname table did not return "
+ "dname when it should!");
+ errors++;
+ continue;
+ }
+
+ if (knot_dname_compare(found_dname, dname) != 0) {
+ diag("Returned dname did not match!");
+ errors++;
+ continue;
+ }
+ }
+
+ /* Search for last dname, it should return NULL. */
+ knot_dname_t *dname =
+ dname_from_test_dname_str(
+ &DNAME_TABLE_DNAMES[DNAME_TABLE_DNAME_COUNT]);
+ assert(dname);
+
+ if (knot_dname_table_find_dname(table, dname) != NULL) {
+ diag("Dname table returned dname when it "
+ "should not be there!");
+ errors++;
+ }
+
+ knot_dname_free(&dname);
+ knot_dname_table_deep_free(&table);
+
+ return (errors == 0);
+}
+
+static const int KNOT_DNAME_TABLE_TEST_COUNT = 3;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_dname_table_tests_count(int argc, char *argv[])
+{
+ return KNOT_DNAME_TABLE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_dname_table_tests_run(int argc, char *argv[])
+{
+ int final_res = 1;
+ int res = 0;
+
+ /* Sort array containing test dnames. */
+ qsort(DNAME_TABLE_DNAMES, DNAME_TABLE_DNAME_COUNT,
+ sizeof(test_dname_t), dname_compare_sort_wrapper);
+
+ ok((res = test_dname_table_new()), "dname table: new");
+ final_res *= res;
+
+ skip(!res, 2);
+
+ ok((res = test_dname_table_adding()), "dname table: adding");
+ final_res *= res;
+
+ ok((res = test_dname_table_find()), "dname table: searching");
+ final_res *= res;
+
+ endskip;
+
+ return final_res;
+}
diff --git a/src/tests/libknot/libknot/dname_table_tests.h b/src/tests/libknot/libknot/dname_table_tests.h
new file mode 100644
index 0000000..f3088e9
--- /dev/null
+++ b/src/tests/libknot/libknot/dname_table_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_DNAME_TABLE_TESTS_H_
+#define _KNOTD_DNAME_TABLE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api dname_table_tests_api;
+
+#endif /* _KNOTD_DNAME_TABLE_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/dname_tests.c b/src/tests/libknot/libknot/dname_tests.c
new file mode 100644
index 0000000..9730756
--- /dev/null
+++ b/src/tests/libknot/libknot/dname_tests.c
@@ -0,0 +1,877 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include "tests/libknot/libknot/dname_tests.h"
+#include "libknot/dname.h"
+#include "libknot/zone/node.h"
+
+static int knot_dname_tests_count(int argc, char *argv[]);
+static int knot_dname_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api dname_tests_api = {
+ "DNS library - dname", //! Unit name
+ &knot_dname_tests_count, //! Count scheduled tests
+ &knot_dname_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+// C will not accept const int in other const definition
+enum { TEST_DOMAINS_OK = 8 };
+
+enum { TEST_DOMAINS_BAD = 4 };
+
+enum { TEST_DOMAINS_NON_FQDN = 6 };
+
+static knot_node_t *NODE_ADDRESS = (knot_node_t *)0xDEADBEEF;
+
+struct test_domain {
+ char *str;
+ char *wire;
+ uint size;
+ char *labels;
+ short label_count;
+};
+
+/*! \warning Do not change the order in those, if you want to test some other
+ * feature with new dname, add it at the end of these arrays.
+ */
+static const struct test_domain
+ test_domains_ok[TEST_DOMAINS_OK] = {
+ { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "test.domain.com.", "\4test\6domain\3com", 17,
+ "\x0\x5\xC", 3 },
+ { ".", "\0", 1,
+ "", 0 },
+ { "foo.bar.net.", "\3foo\3bar\3net", 13,
+ "\x0\x4\x8", 3},
+ { "bar.net.", "\3bar\3net", 9,
+ "\x0\x4", 2}
+};
+
+static const struct test_domain // sizes are strlen()s here
+ test_domains_non_fqdn[TEST_DOMAINS_NON_FQDN] = {
+ { "www", "\3www", 4, "\x0", 1 },
+ { "example", "\7example", 8, "\x0", 1 },
+ { "com", "\3com", 4, "\x0", 1 },
+ { "www.example.com", "\3www\7example\3com", 16, "\x0\x4\xC",
+ 3 },
+ { "some", "\4some", 5, "\x0", 1 },
+ { "example.com", "\7example\3com", 12, "\x0\x8", 2 }
+ };
+
+static const struct test_domain
+ test_domains_bad[TEST_DOMAINS_BAD] = {
+ { NULL, "\2ex\3com", 0, "", 0 },
+ { "ex.com.", NULL, 0, "", 0 },
+ { "ex.com.\5", "\3ex\3com\0\5", 10, "", 0 },
+ { "example.com", "\3example\3com", 12, "\x0\x8", 2 }
+};
+
+static int test_dname_create()
+{
+ knot_dname_t *dname = knot_dname_new();
+ if (dname == NULL
+ || knot_dname_name(dname) != NULL
+ || knot_dname_size(dname) != 0
+ || knot_dname_node(dname, 0) != NULL) {
+ diag("New domain name not initialized properly!");
+ return 0;
+ }
+ knot_dname_free(&dname);
+ if (dname != NULL) {
+ diag("Pointer to the structure not set to"
+ "NULL when deallocating!");
+ return 0;
+ }
+ return 1;
+}
+
+static int test_dname_delete()
+{
+ // how to test this??
+ return 0;
+}
+
+static int check_domain_name(const knot_dname_t *dname,
+ const struct test_domain *test_domains, int i,
+ int check_node)
+{
+ int errors = 0;
+
+ if (dname == NULL) {
+ diag("Domain name #%d not created!", i);
+ return 1;
+ }
+
+ // check size
+ if (knot_dname_size(dname) != test_domains[i].size) {
+ diag("Bad size of the created domain name: %u (should be %u).",
+ knot_dname_size(dname), test_domains[i].size);
+ ++errors;
+ }
+ // check wire format
+ uint size = knot_dname_size(dname);
+ if (strncmp((char *)knot_dname_name(dname),
+ test_domains[i].wire, size) != 0) {
+ diag("The wire format of the created domain name is wrong:"
+ " '%.*s' (should be '%.*s').",
+ size, knot_dname_name(dname),
+ size, test_domains[i].wire);
+ ++errors;
+ }
+ // check labels
+ if (test_domains[i].label_count != dname->label_count) {
+ diag("Label count of the created domain name is wrong:"
+ " %d (should be %d)\n", dname->label_count,
+ test_domains[i].label_count);
+ ++errors;
+ }
+ if (strncmp((char *)dname->labels, test_domains[i].labels,
+ test_domains[i].label_count) != 0) {
+ diag("Label offsets of the created domain name are wrong.\n");
+ ++errors;
+ }
+
+ if (check_node) {
+ if (knot_dname_node(dname, 0) != NODE_ADDRESS) {
+ diag("Node pointer in the created domain name is wrong:"
+ "%p (should be %p)",
+ knot_dname_node(dname, 0), NODE_ADDRESS);
+ ++errors;
+ }
+ }
+
+ return errors;
+}
+
+static int test_dname_create_from_str()
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) {
+ //note("testing domain: %s", test_domains_ok[i].str);
+ dname = knot_dname_new_from_str(test_domains_ok[i].str,
+ strlen(test_domains_ok[i].str), NODE_ADDRESS);
+ errors += check_domain_name(dname, test_domains_ok, i, 1);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_create_from_str_non_fqdn()
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) {
+ //note("testing domain: %s", test_domains_non_fqdn[i].str);
+ dname = knot_dname_new_from_str(test_domains_non_fqdn[i].str,
+ strlen(test_domains_non_fqdn[i].str), NULL);
+ errors += check_domain_name(dname, test_domains_non_fqdn, i, 0);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_cat()
+{
+ int errors = 0;
+
+ /*
+ * This uses three particular dnames from test_domains structure
+ * where the third dname is a concatenation of the first two dnames.
+ */
+
+ knot_dname_t *d1, *d2, *d3;
+
+ d1 = knot_dname_new_from_str(test_domains_non_fqdn[0].str,
+ strlen(test_domains_non_fqdn[0].str), NULL);
+ d2 = knot_dname_new_from_str(test_domains_non_fqdn[1].str,
+ strlen(test_domains_non_fqdn[1].str), NULL);
+ d3 = knot_dname_new_from_str(test_domains_non_fqdn[2].str,
+ strlen(test_domains_non_fqdn[2].str), NULL);
+
+ knot_dname_cat(d1, d2);
+ knot_dname_cat(d1, d3);
+
+ errors += check_domain_name(d1, test_domains_non_fqdn, 3, 0);
+
+ knot_dname_free(&d1);
+ knot_dname_free(&d2);
+ knot_dname_free(&d3);
+
+ /*
+ * Same thing as above, only different case.
+ */
+
+ d1 = knot_dname_new_from_str(test_domains_non_fqdn[4].str,
+ strlen(test_domains_non_fqdn[4].str),
+ NODE_ADDRESS);
+
+ d2 = knot_dname_new_from_str(test_domains_ok[4].str,
+ strlen(test_domains_ok[4].str),
+ NODE_ADDRESS);
+
+ knot_dname_cat(d1, d2);
+
+ errors += check_domain_name(d1, test_domains_ok, 1, 1);
+
+ knot_dname_free(&d1);
+ knot_dname_free(&d2);
+
+ return (errors == 0);
+}
+
+static int test_dname_left_chop()
+{
+ int errors = 0;
+
+ /* Uses same principle as test_dname_cat(), only reversed */
+
+ /* TODO this would maybe deserver separate structure */
+
+ knot_dname_t *d1;
+
+ d1 = knot_dname_new_from_str(test_domains_ok[1].str,
+ strlen(test_domains_ok[1].str),
+ NODE_ADDRESS);
+
+ knot_dname_t *chopped;
+
+ chopped = knot_dname_left_chop(d1);
+
+ errors += check_domain_name(chopped, test_domains_ok, 4, 0);
+
+ knot_dname_free(&d1);
+ knot_dname_free(&chopped);
+
+ d1 = knot_dname_new_from_str(test_domains_non_fqdn[3].str,
+ strlen(test_domains_non_fqdn[3].str),
+ NODE_ADDRESS);
+
+ chopped = knot_dname_left_chop(d1);
+
+ errors += check_domain_name(chopped, test_domains_non_fqdn, 5, 0);
+
+ knot_dname_free(&d1);
+ knot_dname_free(&chopped);
+
+ return (errors == 0);
+}
+
+static int test_dname_create_from_wire()
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) {
+ assert(strlen(test_domains_ok[i].wire) + 1 ==
+ test_domains_ok[i].size);
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ errors += check_domain_name(dname, test_domains_ok, i, 1);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_to_str()
+{
+ int errors = 0;
+
+ /*
+ * Converts dname wireformat to string represenation, which is compared
+ * with entries in test_domains structure.
+ */
+
+ knot_dname_t *dname = NULL;
+
+ for (int i = 0; i < TEST_DOMAINS_OK && errors == 0; ++i) {
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ char *name_str = knot_dname_to_str(dname);
+ if (strcmp(name_str, test_domains_ok[i].str) != 0) {
+ diag("Presentation format of domain name wrong:"
+ " %s (should be %s)",
+ name_str, test_domains_ok[i].str);
+ ++errors;
+ }
+ free(name_str);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+/* called by lives_ok */
+static int test_faulty_data()
+{
+ knot_dname_t *dname = NULL;
+
+ /*
+ * This takes dnames from test_domains_bad array, which contains
+ * malformed dnames. TODO add something like: 2www3foo - it's gonna fail
+ */
+
+ for (int i = 0; i < TEST_DOMAINS_BAD; i++) {
+
+ if (test_domains_bad[i].str != NULL) {
+ dname = knot_dname_new_from_str(
+ test_domains_bad[i].str,
+ strlen(test_domains_bad[i].str),
+ NODE_ADDRESS);
+ } else {
+ dname = knot_dname_new_from_str(
+ test_domains_bad[i].str, 0, NODE_ADDRESS);
+ }
+
+ knot_dname_free(&dname);
+
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_bad[i].wire,
+ test_domains_bad[i].size, NODE_ADDRESS);
+
+ knot_dname_free(&dname);
+ }
+
+ return 1; //did it get here? success
+}
+
+static int test_dname_compare()
+{
+ knot_dname_t *dnames[TEST_DOMAINS_OK];
+
+ /* This uses particular dnames from TEST_DOMAINS_OK array */
+
+ for (int i = 0; i < TEST_DOMAINS_OK; ++i) {
+ dnames[i] = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ }
+
+ int errors = 0;
+ /* abc < some */
+ if (knot_dname_compare(dnames[0], dnames[1]) >= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /* abc.test.domain.com. < foo.bar.net. */
+ if (knot_dname_compare(dnames[0], dnames[6]) >= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /* foo.bar.net. < . */
+ if (knot_dname_compare(dnames[5], dnames[0]) >= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /* bar.net. < foo.bar.net. */
+ if (knot_dname_compare(dnames[7], dnames[6]) >= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /* some == some */
+ if (knot_dname_compare(dnames[1], dnames[3]) != 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /*xyz > some */
+ if (knot_dname_compare(dnames[2], dnames[1]) <= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ /*foo.bar.net. > xyz.test.domain.com. */
+ if (knot_dname_compare(dnames[6], dnames[3]) <= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+// /* xyz.test.domain.com. > . */
+// if (knot_dname_compare(dnames[3], dnames[5]) <= 0) {
+// diag("Dname comparison error");
+// errors++;
+// }
+
+ /* bar.net. < foo.bar.net. */
+ if (knot_dname_compare(dnames[6], dnames[7]) <= 0) {
+ diag("Dname comparison error");
+ errors++;
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ knot_dname_free(&dnames[i]);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_is_fqdn()
+{
+ int errors = 0;
+
+ knot_dname_t *dname;
+
+ /* All dnames in TEST_DOMAINS_OK are fqdn */
+
+ for (int i = 0; i < TEST_DOMAINS_OK && !errors; ++i) {
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ errors += !knot_dname_is_fqdn(dname);
+ knot_dname_free(&dname);
+ }
+
+ /* None of the following dnames should be fqdn */
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN && !errors; ++i) {
+ dname = knot_dname_new_from_str(test_domains_non_fqdn[i].str,
+ strlen(test_domains_non_fqdn[i].str), NULL);
+ errors += knot_dname_is_fqdn(dname);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_is_subdomain()
+{
+ int errors = 0;
+
+ knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK];
+ knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN];
+
+ for (int i = 0; i < TEST_DOMAINS_OK; ++i) {
+ dnames_fqdn[i] = knot_dname_new_from_wire(
+ (const uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NULL);
+ assert(dnames_fqdn[i] != NULL);
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) {
+ dnames_non_fqdn[i] = knot_dname_new_from_str(
+ test_domains_non_fqdn[i].str,
+ test_domains_non_fqdn[i].size, NULL);
+ assert(dnames_non_fqdn[i] != NULL);
+ }
+
+ // fqdn names 0 - 3 should be subdomains of name 4
+ knot_dname_t *parent = dnames_fqdn[4];
+ for (int i = 0; i < 3; ++i) {
+ if (!knot_dname_is_subdomain(dnames_fqdn[i], parent)) {
+ diag("(fqdn 1-%d) "
+ "Name %s was not considered subdomain of %s", i,
+ knot_dname_name(dnames_fqdn[i]),
+ knot_dname_name(parent));
+ ++errors;
+ }
+ }
+
+ // fqdn names 0 - 4 should be subdomains of name 5 (root)
+ parent = dnames_fqdn[5];
+ for (int i = 0; i < 4; ++i) {
+ if (!knot_dname_is_subdomain(dnames_fqdn[i], parent)) {
+ diag("(fqdn 2-%d) "
+ "Name %s was not considered subdomain of %s", i,
+ knot_dname_name(dnames_fqdn[i]),
+ knot_dname_name(parent));
+ ++errors;
+ }
+ }
+
+ // non-fqdn names 3 and 5 should be subdomains of non-fqdn name 2
+ parent = dnames_non_fqdn[2];
+ if (!knot_dname_is_subdomain(dnames_non_fqdn[3], parent)) {
+ diag("(non-fqdn 1) "
+ "Name %.*s was not considered subdomain of %.*s",
+ knot_dname_size(dnames_non_fqdn[3]),
+ knot_dname_name(dnames_non_fqdn[3]),
+ knot_dname_size(parent),
+ knot_dname_name(parent));
+ ++errors;
+ }
+ if (!knot_dname_is_subdomain(dnames_non_fqdn[5], parent)) {
+ diag("(non-fqdn 2) "
+ "Name %.*s was not considered subdomain of %.*s",
+ knot_dname_size(dnames_non_fqdn[5]),
+ knot_dname_name(dnames_non_fqdn[5]),
+ knot_dname_size(parent),
+ knot_dname_name(parent));
+ ++errors;
+ }
+
+ // non-fqdn name 3 should be subdomain of non-fqdn name 5
+ parent = dnames_non_fqdn[5];
+ if (!knot_dname_is_subdomain(dnames_non_fqdn[3], parent)) {
+ diag("(non-fqdn 3) "
+ "Name %.*s was not considered subdomain of %.*s",
+ knot_dname_size(dnames_non_fqdn[3]),
+ knot_dname_name(dnames_non_fqdn[3]),
+ knot_dname_size(parent),
+ knot_dname_name(parent));
+ ++errors;
+ }
+
+ // identical names should not be considered subdomains
+ if (knot_dname_is_subdomain(dnames_fqdn[0], dnames_fqdn[0])) {
+ diag("(identical names) "
+ "Name %s was considered subdomain of itself",
+ knot_dname_name(dnames_fqdn[0]));
+ ++errors;
+ }
+ if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_fqdn[3])) {
+ diag("(identical names) "
+ "Name %s was considered subdomain of %s",
+ knot_dname_name(dnames_fqdn[1]),
+ knot_dname_name(dnames_fqdn[3]));
+ ++errors;
+ }
+
+ // fqdn name should not be considered subdomain of non-fqdn name
+ if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_non_fqdn[2])) {
+ diag("(fqdn subdomain of non-fqdn) "
+ "Name %s was considered subdomain of %.*s",
+ knot_dname_name(dnames_fqdn[1]),
+ knot_dname_size(dnames_non_fqdn[2]),
+ knot_dname_name(dnames_non_fqdn[2]));
+ ++errors;
+ }
+
+ // non-fqdn name should not be considered subdomain of fqdn name
+ if (knot_dname_is_subdomain(dnames_fqdn[1], dnames_non_fqdn[2])) {
+ diag("(non-fqdn subdomain of fqdn) "
+ "Name %s was considered subdomain of %.*s",
+ knot_dname_name(dnames_fqdn[1]),
+ knot_dname_size(dnames_non_fqdn[2]),
+ knot_dname_name(dnames_non_fqdn[2]));
+ ++errors;
+ }
+
+ // parent name should not be considered subdomain of its subdomain
+ if (knot_dname_is_subdomain(dnames_fqdn[4], dnames_fqdn[0])) {
+ diag("(ancestor subdomain of name) "
+ "Name %s was considered subdomain of %s",
+ knot_dname_name(dnames_fqdn[4]),
+ knot_dname_name(dnames_fqdn[0]));
+ ++errors;
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_OK; ++i) {
+ knot_dname_free(&dnames_fqdn[i]);
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) {
+ knot_dname_free(&dnames_non_fqdn[i]);
+ }
+
+ return (errors == 0);
+}
+
+static int check_wires(const uint8_t *wire1, uint size1,
+ uint8_t *wire2, uint size2)
+{
+ if (size1 != size2) {
+ return 0;
+ }
+
+ int i;
+
+ for (i = 0; (i < size1); i++) {
+ if (wire1[i] != wire2[i]) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*!< \note not to be run separately */
+static int test_dname_name(knot_dname_t **dnames_fqdn,
+ knot_dname_t **dnames_non_fqdn)
+{
+ assert(dnames_fqdn);
+ assert(dnames_non_fqdn);
+
+ int errors = 0;
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ const uint8_t *tmp_name;
+
+ tmp_name = knot_dname_name(dnames_fqdn[i]);
+ if (!check_wires(tmp_name, dnames_fqdn[i]->size,
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size)) {
+ diag("Got bad name value from structure: "
+ "%s, should be: %s. Sizes: %d and: %d",
+ tmp_name, test_domains_ok[i].wire,
+ dnames_fqdn[i]->size,
+ test_domains_ok[i].size);
+ errors++;
+ }
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ const uint8_t *tmp_name;
+ tmp_name = knot_dname_name(dnames_non_fqdn[i]);
+ if (!check_wires(tmp_name, dnames_non_fqdn[i]->size - 1,
+ (uint8_t *)test_domains_non_fqdn[i].wire,
+ test_domains_non_fqdn[i].size)) {
+ diag("Got bad name value from structure: "
+ "%s, should be: %s. Sizes: %d and %d\n",
+ tmp_name, test_domains_non_fqdn[i].wire,
+ dnames_non_fqdn[i]->size,
+ test_domains_non_fqdn[i].size);
+// hex_print(dnames_non_fqdn[i]->name,
+// dnames_non_fqdn[i]->size);
+// hex_print(test_domains_non_fqdn[i].wire,
+// test_domains_non_fqdn[i].size);
+// diag("%s and %s\n",
+// knot_dname_to_str(dnames_non_fqdn[i]),
+// test_domains_non_fqdn[i]);
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+/* \note not to be run separately */
+static int test_dname_size(knot_dname_t **dnames_fqdn,
+ knot_dname_t **dnames_non_fqdn)
+{
+ assert(dnames_fqdn);
+ assert(dnames_non_fqdn);
+
+ int errors = 0;
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ uint8_t tmp_size;
+ if ((tmp_size = knot_dname_size(dnames_fqdn[i])) !=
+ test_domains_ok[i].size) {
+ diag("Got bad size value from structure: "
+ "%u, should be: %u",
+ tmp_size, test_domains_ok[i].size);
+ errors++;
+ }
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ uint8_t tmp_size;
+ if ((tmp_size = knot_dname_size(dnames_non_fqdn[i])) !=
+ test_domains_non_fqdn[i].size) {
+ diag("Got bad size value from structure: "
+ "%u, should be: %u",
+ tmp_size, test_domains_non_fqdn[i].size);
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+/* \note not to be run separately */
+static int test_dname_node(knot_dname_t **dnames_fqdn,
+ knot_dname_t **dnames_non_fqdn)
+{
+ assert(dnames_fqdn);
+ assert(dnames_non_fqdn);
+
+ int errors = 0;
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ const knot_node_t *tmp_node;
+ if ((tmp_node = knot_dname_node(dnames_fqdn[i], 0)) !=
+ NODE_ADDRESS) {
+ diag("Got bad node value from structure: "
+ "%p, should be: %p",
+ tmp_node, NODE_ADDRESS);
+ errors++;
+ }
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ const knot_node_t *tmp_node;
+ if ((tmp_node = knot_dname_node(dnames_non_fqdn[i], 0)) !=
+ NODE_ADDRESS) {
+ diag("Got bad node value from structure: "
+ "%s, should be: %s",
+ tmp_node, NODE_ADDRESS);
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+static int test_dname_getters(uint type)
+{
+ int errors = 0;
+
+ knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK];
+ knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN];
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ dnames_fqdn[i] = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[i].wire,
+ test_domains_ok[i].size, NODE_ADDRESS);
+ assert(dnames_fqdn[i] != NULL);
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ printf("Creating dname: %s size: %d\n", test_domains_non_fqdn[i].wire, test_domains_non_fqdn[i].size);
+ dnames_non_fqdn[i] = knot_dname_new_from_str(
+ test_domains_non_fqdn[i].str,
+ test_domains_non_fqdn[i].size, NODE_ADDRESS);
+ assert(dnames_non_fqdn[i] != NULL);
+ }
+
+ switch (type) {
+ case 0: {
+ errors += test_dname_name(dnames_fqdn, dnames_non_fqdn);
+ break;
+ }
+
+ case 1: {
+ errors += test_dname_size(dnames_fqdn, dnames_non_fqdn);
+ break;
+ }
+
+ case 2: {
+ errors += test_dname_node(dnames_fqdn, dnames_non_fqdn);
+ break;
+ }
+ } /* switch */
+
+ for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+ knot_dname_free(&dnames_fqdn[i]);
+ }
+
+ for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+ knot_dname_free(&dnames_non_fqdn[i]);
+ }
+
+ return (errors == 0);
+}
+
+static const int KNOT_DNAME_TEST_COUNT = 15;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_dname_tests_count(int argc, char *argv[])
+{
+ return KNOT_DNAME_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_dname_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_str = 0,
+ res_wire = 0,
+ res_str_non_fqdn = 0,
+ res_final = 1;
+
+ res = test_dname_create();
+ ok(res, "dname: create empty");
+ res_final *= res;
+
+ skip(!res, 12);
+
+ todo();
+
+ ok((res = test_dname_delete()), "dname: delete");
+ //res_final *= res;
+
+ endtodo;
+
+ ok((res_str = test_dname_create_from_str()), "dname: create from str");
+ ok((res_wire = test_dname_create_from_wire()),
+ "dname: create from wire");
+ ok((res_str_non_fqdn = test_dname_create_from_str_non_fqdn()),
+ "dname: create from str non fqdn");
+ res_final *= res_str;
+ res_final *= res_wire;
+ res_final *= res_str_non_fqdn;
+
+ todo();
+ res = test_dname_getters(0);
+ ok(res, "dname: name");
+ endtodo;
+
+ todo();
+ res = test_dname_getters(1);
+ ok(res, "dname: size");
+ endtodo;
+
+ res = test_dname_getters(2);
+ ok(res, "dname: node");
+
+ skip(!res_str || !res_wire || !res_str_non_fqdn, 2);
+
+ ok((res = test_dname_to_str()), "dname: convert to str");
+ res_final *= res;
+
+ lives_ok(test_faulty_data(); , "dname: faulty data test");
+
+ endskip; /* !res_str || !res_wire */
+
+ ok((res = test_dname_compare()), "dname: compare");
+ res_final *= res;
+
+ ok((res = test_dname_cat()), "dname: cat");
+ res_final *= res;
+
+ ok((res = test_dname_is_fqdn()), "dname: fqdn");
+ res_final *= res;
+
+ ok((res = test_dname_left_chop()), "dname: left chop");
+ res_final *= res;
+
+ ok((res = test_dname_is_subdomain()), "dname: is subdomain");
+ res_final *= res;
+
+ endskip; /* create failed */
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/dname_tests.h b/src/tests/libknot/libknot/dname_tests.h
new file mode 100644
index 0000000..a7d75aa
--- /dev/null
+++ b/src/tests/libknot/libknot/dname_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_DNAME_TESTS_H_
+#define _KNOTD_DNAME_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api dname_tests_api;
+
+#endif /* _KNOTD_DNAME_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/edns_tests.c b/src/tests/libknot/libknot/edns_tests.c
new file mode 100644
index 0000000..ac5d130
--- /dev/null
+++ b/src/tests/libknot/libknot/edns_tests.c
@@ -0,0 +1,596 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "tests/libknot/libknot/edns_tests.h"
+#include "libknot/common.h"
+#include "libknot/edns.h"
+
+static int knot_edns_tests_count(int argc, char *argv[]);
+static int knot_edns_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api edns_tests_api = {
+ "DNS library - EDNS", //! Unit name
+ &knot_edns_tests_count, //! Count scheduled tests
+ &knot_edns_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+enum { TEST_EDNS = 1, OPTION_COUNT = 3 };
+
+struct test_edns_options {
+ uint16_t code;
+ uint16_t length;
+ uint8_t *data;
+};
+
+struct test_edns {
+ struct test_edns_options *options;
+ uint16_t payload;
+ uint8_t ext_rcode;
+ uint8_t version;
+ uint16_t flags;
+ short option_count;
+ short options_max;
+ short size;
+};
+
+typedef struct test_edns test_edns_t;
+
+struct test_edns_options test_options_data[OPTION_COUNT] = {
+ {5, 7, (uint8_t *)"123456"},
+ {4, 3, (uint8_t *)"12"},
+ {1, 5, (uint8_t *)"13333"}
+};
+
+test_edns_t test_edns_data[TEST_EDNS] = {
+{ NULL, 4096, 2, 0, 0, 0, 10, 11}
+};
+
+enum edns_mask {
+ KNOT_EDNS_DO_MASK = (uint16_t)0x8000
+};
+
+/* Creates actual knot_opt_rr_t variable from test_edns_t variable */
+static knot_opt_rr_t *opt_rr_from_test_edns(test_edns_t *test_edns)
+{
+ knot_opt_rr_t *ret = knot_edns_new();
+
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ ret->flags = test_edns->flags;
+ ret->ext_rcode = test_edns->ext_rcode;
+ ret->payload = test_edns->payload;
+ ret->version = test_edns->version;
+
+ for (int i = 0; i < test_edns->option_count; i++) {
+ if (knot_edns_add_option(ret, test_edns->options[i].code,
+ test_edns->options[i].length,
+ test_edns->options[i].data) != 0) {
+ knot_edns_free(&ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+/* simple wire compare - 0 if same, 1 otherwise */
+static int edns_compare_wires(uint8_t *wire1,
+ uint8_t *wire2,
+ uint16_t length)
+{
+ for (uint i = 0; i < length; i++) {
+ if (wire1[i] != wire2[i]) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int check_edns(const knot_opt_rr_t *edns,
+ const test_edns_t *test_edns)
+{
+ if (edns->option_count != test_edns->option_count) {
+ diag("Option count is wrong");
+ return -1;
+ }
+
+ for (int i = 0; i < edns->option_count; i++) {
+ /* check options */
+ if (edns->options[i].code != test_edns->options[i].code) {
+ diag("Code in options is wrong");
+ return -1;
+ }
+
+ if (edns->options[i].length != test_edns->options[i].length) {
+ diag("Length in options is wrong");
+ return -1;
+ }
+
+ if (edns_compare_wires(edns->options[i].data,
+ test_edns->options[i].data,
+ edns->options[i].length) != 0) {
+ diag("Data in options are wrong");
+ return -1;
+ }
+ }
+
+ if (edns->version != test_edns->version) {
+ diag("Version is wrong");
+ return -1;
+ }
+
+ if (edns->flags != test_edns->flags) {
+ diag("Flags are wrong");
+ return -1;
+ }
+
+ if (edns->size != test_edns->size) {
+ diag("Size is wrong");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int test_edns_get_payload(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_get_payload(edns) !=
+ test_edns->payload) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_get_ext_rcode(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_get_ext_rcode(edns) !=
+ test_edns->ext_rcode) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_get_flags(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_get_flags(edns) !=
+ test_edns->flags) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_get_version(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_get_version(edns) !=
+ test_edns->version) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_do(const knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ if (knot_edns_do(edns) !=
+ (test_edns->flags & KNOT_EDNS_DO_MASK)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_size(knot_opt_rr_t *edns, test_edns_t *test_edns)
+{
+ if (knot_edns_size(edns) !=
+ test_edns->size) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_set_payload(knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ knot_edns_set_payload(edns, test_edns->payload);
+
+ if (edns->payload !=
+ test_edns->payload) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_set_ext_rcode(knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ knot_edns_set_ext_rcode(edns, test_edns->ext_rcode);
+ if (edns->ext_rcode !=
+ test_edns->ext_rcode) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_set_version(knot_opt_rr_t *edns,
+ test_edns_t *test_edns)
+{
+ knot_edns_set_version(edns,
+ test_edns->version);
+
+ if (edns->version !=
+ test_edns->version) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_set_do(knot_opt_rr_t *edns)
+{
+ knot_edns_set_do(edns);
+
+ if (!knot_edns_do(edns)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int test_edns_getters(uint type)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_EDNS; i++) {
+ knot_opt_rr_t *edns =
+ opt_rr_from_test_edns(&(test_edns_data[i]));
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ switch(type) {
+ case 0:
+ if (test_edns_get_payload(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong payload!");
+ errors++;
+ }
+ break;
+ case 1:
+ if (test_edns_get_ext_rcode(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong extended RCODE!");
+ errors++;
+ }
+ break;
+ case 2:
+ if (test_edns_get_flags(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong flags!");
+
+ errors++;
+ }
+ break;
+ case 3:
+ if (test_edns_get_version(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong version!");
+ errors++;
+ }
+ break;
+ case 4:
+ if (test_edns_do(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong DO bit!");
+ errors++;
+ }
+ break;
+ case 5:
+ if (test_edns_size(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Got wrong size!");
+ errors++;
+ }
+ break;
+ default:
+ diag("Unknown option");
+ errors++;
+ } /* switch */
+
+ knot_edns_free(&edns);
+ }
+
+ return (errors == 0);
+}
+
+static int test_edns_setters(uint type)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_EDNS; i++) {
+ knot_opt_rr_t *edns =
+ opt_rr_from_test_edns(&(test_edns_data[i]));
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ switch(type) {
+ case 0:
+ if (test_edns_set_payload(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Set wrong payload!");
+ errors++;
+ }
+ break;
+ case 1:
+ if (test_edns_set_ext_rcode(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Set wrong ext_rcode");
+ errors++;
+ }
+ break;
+ case 2:
+ if (test_edns_set_version(edns,
+ &test_edns_data[i]) != 1) {
+ diag("Set wrong version!");
+ errors++;
+ }
+ break;
+ case 3:
+ if (test_edns_set_do(edns) != 1) {
+ diag("Set wrong DO bit!");
+ errors++;
+ }
+ break;
+ default:
+ diag("Unknown option");
+ errors++;
+ } /* switch */
+
+ knot_edns_free(&edns);
+ }
+
+ return (errors == 0);
+}
+
+static int test_edns_wire()
+{
+ /*
+ * Tests to_wire and from_wire in one test.
+ */
+ for (int i = 0; i < TEST_EDNS; i++) {
+ /* Creates instance from test_edns_t. */
+ knot_opt_rr_t *edns =
+ opt_rr_from_test_edns(&(test_edns_data[i]));
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return -1;
+ }
+
+ uint8_t *wire = NULL;
+ wire = malloc(sizeof(uint8_t) * edns->size);
+ CHECK_ALLOC_LOG(wire, 0);
+
+ /* Converts EDNS to wire. */
+ short wire_size = knot_edns_to_wire(edns, wire, 100);
+
+ if (wire_size == -1) {
+ diag("Could not create EDNS wire");
+ return 0;
+ }
+
+ knot_opt_rr_t *edns_from_wire = knot_edns_new();
+ if (edns == NULL) {
+ return 0;
+ }
+
+ /* TODO use some constant */
+ /* Creates new EDNS from wire */
+ if (knot_edns_new_from_wire(edns_from_wire,
+ wire,
+ 100) <= 0) {
+ diag("Could not create from wire");
+ return 0;
+ }
+
+ /* Checks whether EDNS created from wire is the same */
+ if (check_edns(edns_from_wire,
+ &(test_edns_data[i])) != 0) {
+ diag("EDNS created from wire is different from the "
+ "original one");
+ }
+
+ free(wire);
+ knot_edns_free(&edns_from_wire);
+ knot_edns_free(&edns);
+ }
+ return 1;
+}
+
+static int test_edns_add_option()
+{
+ /*
+ * Create empty EDNS and add options one by one, testing their presence.
+ */
+ for (int i = 0; i < TEST_EDNS; i++) {
+ knot_opt_rr_t *edns = knot_edns_new();
+ assert(edns->option_count == 0);
+
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return 0;
+ }
+
+ for (int j = 0; j < test_edns_data[i].option_count; j++) {
+ if (knot_edns_add_option(edns,
+ test_edns_data[i].options[j].code,
+ test_edns_data[i].options[j].length,
+ test_edns_data[i].options[j].
+ data) != 0) {
+ diag("Could not add option");
+ return 0;
+ }
+
+ if (edns->options[j].code !=
+ test_edns_data[i].options[j].code) {
+ diag("Option code wrongly added!");
+ return 0;
+ }
+
+ if (edns->options[j].length !=
+ test_edns_data[i].options[j].length) {
+ diag("Option length wrongly added!");
+ return 0;
+ }
+
+ if (edns_compare_wires(edns->options[j].data,
+ test_edns_data[i].
+ options[j].data,
+ edns->options[j].length) != 0) {
+ diag("Option wire wrongly added!");
+ return 0;
+ }
+ }
+ knot_edns_free(&edns);
+ }
+ return 1;
+}
+
+static int test_edns_has_option()
+{
+ /*
+ * Create empty EDNS and add options one by one, testing their presence
+ */
+ for (int i = 0; i < TEST_EDNS; i++) {
+ knot_opt_rr_t *edns = knot_edns_new();
+ assert(edns->option_count == 0);
+
+ if (edns == NULL) {
+ ERR_ALLOC_FAILED;
+ return 0;
+ }
+
+ for (int j = 0; j < test_edns_data[i].option_count; j++) {
+ if (knot_edns_add_option(edns,
+ test_edns_data[i].options[j].code,
+ test_edns_data[i].options[j].length,
+ test_edns_data[i].options[j].
+ data) != 0) {
+ diag("Could not add option");
+ return 0;
+ }
+
+ if (knot_edns_has_option(edns,
+ test_edns_data[i].options[j].code) != 1) {
+ diag("Option not found!");
+ return 0;
+ }
+ }
+ knot_edns_free(&edns);
+ }
+ return 1;
+}
+
+static const int KNOT_EDNS_TESTS_COUNT = 12;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_edns_tests_count(int argc, char *argv[])
+{
+ return KNOT_EDNS_TESTS_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_edns_tests_run(int argc, char *argv[])
+{
+ int res = 0;
+ int res_final = 1;
+
+ res = test_edns_getters(0);
+ ok(res, "ends: get payload");
+ res_final *= res;
+
+ res = test_edns_getters(1);
+ ok(res, "ends: get extenden RCODE");
+ res_final *= res;
+
+ res = test_edns_getters(2);
+ ok(res, "ends: get flags");
+ res_final *= res;
+
+ res = test_edns_getters(3);
+ ok(res, "ends: get version");
+ res_final *= res;
+
+ res = test_edns_getters(4);
+ ok(res, "ends: do");
+ res_final *= res;
+
+ res = test_edns_getters(5);
+ ok(res, "ends: size");
+ res_final *= res;
+
+ res = test_edns_setters(0);
+ ok(res, "ends: set payload");
+ res_final *= res;
+
+ res = test_edns_setters(1);
+ ok(res, "ends: set extended RCODE");
+ res_final *= res;
+
+ res = test_edns_setters(2);
+ ok(res, "ends: set version");
+ res_final *= res;
+
+ res = test_edns_setters(3);
+ ok(res, "ends: set DO");
+ res_final *= res;
+
+ res = test_edns_add_option();
+ ok(res, "ends: add option");
+ res_final *= res;
+
+ res = test_edns_has_option();
+ ok(res, "ends: has option");
+ res_final *= res;
+
+ res = test_edns_wire();
+ ok(res, "ends: to_wire and from_wire");
+ res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/edns_tests.h b/src/tests/libknot/libknot/edns_tests.h
new file mode 100644
index 0000000..4553234
--- /dev/null
+++ b/src/tests/libknot/libknot/edns_tests.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file edns_tests.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * Contains unit tests for ENDS API
+ *
+ * Contains tests for:
+ * - ENDS API
+ */
+#ifndef _KNOTD__EDNS_TESTS_H_
+#define _KNOTD__EDNS_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api edns_tests_api;
+
+#endif /* _KNOTD__EDNS_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/node_tests.c b/src/tests/libknot/libknot/node_tests.c
new file mode 100644
index 0000000..f04a202
--- /dev/null
+++ b/src/tests/libknot/libknot/node_tests.c
@@ -0,0 +1,344 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tests/libknot/libknot/node_tests.h"
+#include "libknot/dname.h"
+#include "libknot/zone/node.h"
+#include "libknot/util/descriptor.h"
+
+static int knot_node_tests_count(int argc, char *argv[]);
+static int knot_node_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api node_tests_api = {
+ "DNS library - node", //! Unit name
+ &knot_node_tests_count, //! Count scheduled tests
+ &knot_node_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+// C will not accept const int in other const definition
+enum { TEST_NODES = 2, RRSETS = 5};
+
+struct test_node {
+ knot_dname_t owner;
+ knot_node_t *parent;
+ uint size;
+};
+
+static knot_dname_t test_dnames[TEST_NODES] = {
+ {{}, (uint8_t *)"\3www\7example\3com", 17},
+ {{}, (uint8_t *)"\3www\7example\3com", 17}
+};
+
+static struct test_node test_nodes[TEST_NODES] = {
+ {{{}, (uint8_t *)"\3com", 4}, (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\3www\7example\3com", 17}, (knot_node_t *)NULL}
+};
+
+static knot_rrset_t rrsets[RRSETS] = {
+ {&test_dnames[0], 1, 1, 3600, NULL, NULL},
+ {&test_dnames[1], 2, 1, 3600, NULL, NULL},
+ {&test_dnames[1], 7, 1, 3600, NULL, NULL},
+ {&test_dnames[1], 3, 1, 3600, NULL, NULL},
+ {&test_dnames[1], 9, 1, 3600, NULL, NULL}
+};
+
+static int test_node_create()
+{
+ /* Tests creation of node by comparing with test_node struct */
+ knot_node_t *tmp;
+ int errors = 0;
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ tmp = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+ if (tmp == NULL ||
+ tmp->owner != &test_nodes[i].owner ||
+ tmp->parent != test_nodes[i].parent ||
+ tmp->rrset_tree == NULL) {
+ errors++;
+ diag("Failed to create node structure");
+ }
+ knot_node_free(&tmp, 0, 0);
+ }
+ return (errors == 0);
+}
+
+static int test_node_add_rrset()
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ /* create node from test_node structure */
+ tmp = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+ rrset = &rrsets[i];
+ if (knot_node_add_rrset(tmp, rrset, 0) < 0) {
+ errors++;
+ diag("Failed to insert rrset into node");
+ }
+
+ /* check if rrset is really there */
+
+ const knot_rrset_t *rrset_from_node = NULL;
+ if ((rrset_from_node =
+ knot_node_rrset(tmp, rrset->type)) == NULL) {
+ errors++;
+ diag("Inserted rrset could not be found");
+ continue;
+ }
+
+ /* compare rrset from node with original rrset */
+
+ const knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+
+ int cmp = 0;
+
+ if ((rrset_from_node->rdata == NULL) &&
+ (rrset->rdata == NULL)) {
+ cmp = 0;
+ } else if ((rrset_from_node->rdata != NULL) &&
+ (rrset->rdata != NULL)) {
+ cmp = knot_rdata_compare(rrset_from_node->rdata,
+ rrset->rdata,
+ desc->wireformat);
+ } else { /* one is not NULL and other is -> error */
+ cmp = 1;
+ }
+
+ if (!((rrset_from_node->type == rrset->type) &&
+ (rrset_from_node->rclass == rrset->rclass) &&
+ (rrset_from_node->ttl == rrset->ttl) &&
+ (rrset_from_node->rrsigs == rrset->rrsigs) &&
+ (cmp == 0))) {
+ errors++;
+ diag("Values in found rrset are wrong");
+ }
+
+ knot_node_free(&tmp, 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+static int test_node_get_rrset()
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+
+ knot_node_t *nodes[TEST_NODES];
+
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ tmp = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+ nodes[i] = tmp;
+ for (int j = 0; j < RRSETS; j++) {
+ knot_node_add_rrset(tmp, &rrsets[j], 0);
+ }
+ }
+
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ for (int j = 0; j < RRSETS; j++) {
+ rrset = &rrsets[j];
+ if (knot_node_rrset(nodes[i], rrset->type)
+ != rrset) {
+ errors++;
+ diag("Failed to get proper rrset from node");
+ }
+ }
+ knot_node_free(&nodes[i], 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+static int test_node_get_parent()
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+
+ knot_node_t *nodes[TEST_NODES];
+
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ tmp = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+ nodes[i] = tmp;
+ rrset = &rrsets[i];
+ knot_node_add_rrset(tmp, rrset, 0);
+ }
+
+ for (int i = 0; i < TEST_NODES && !errors; i++) {
+ rrset = &rrsets[i];
+ if (knot_node_parent(nodes[i], 0) != test_nodes[i].parent) {
+ errors++;
+ diag("Failed to get proper parent from node");
+ }
+ knot_node_free(&nodes[i], 0, 0);
+ }
+ return (errors == 0);
+}
+
+static int test_node_sorting()
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+
+ tmp = knot_node_new(&test_nodes[0].owner, test_nodes[0].parent, 0);
+
+ /* Will add rrsets to node. */
+
+ for (int i = 0; i < RRSETS && !errors; i++) {
+ rrset = &rrsets[i];
+ knot_node_add_rrset(tmp, rrset, 0);
+ }
+
+// const skip_node_t *node = skip_first(tmp->rrsets);
+
+// int last = *((uint16_t *)node->key);
+
+// /* TODO there is now an API function knot_node_rrsets ... */
+
+// /* Iterates through skip list and checks, whether it is sorted. */
+
+// while ((node = skip_next(node)) != NULL) {
+// if (last > *((uint16_t *)node->key)) {
+// errors++;
+// diag("RRset sorting error");
+// }
+// last = *((uint16_t *)node->key);
+// }
+
+ knot_node_free(&tmp, 0, 0);
+ return (errors == 0);
+}
+
+static int test_node_delete()
+{
+ int errors = 0;
+
+ knot_node_t *tmp_node;
+
+ for (int i = 0; i < TEST_NODES; i++) {
+ tmp_node = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+
+ knot_node_free(&tmp_node, 0, 0);
+
+ errors += (tmp_node != NULL);
+ }
+
+ return (errors == 0);
+}
+
+static int test_node_set_parent()
+{
+ knot_node_t *tmp_parent = knot_node_new(NULL, NULL, 0);
+ int errors = 0;
+
+ knot_node_t *tmp_node;
+
+ for (int i = 0; i < TEST_NODES; i++) {
+ tmp_node = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+
+ knot_node_set_parent(tmp_node, tmp_parent);
+
+ if (tmp_node->parent != tmp_node->parent) {
+ diag("Parent node is wrongly set.");
+ errors++;
+ }
+ knot_node_free(&tmp_node, 0, 0);
+ }
+ knot_node_free(&tmp_parent, 0, 0);
+ return (errors == 0);
+}
+
+static int test_node_free_rrsets()
+{
+ int errors = 0;
+
+ knot_node_t *tmp_node;
+
+ for (int i = 0; i < TEST_NODES; i++) {
+ tmp_node = knot_node_new(&test_nodes[i].owner,
+ test_nodes[i].parent, 0);
+
+ knot_node_free_rrsets(tmp_node, 0);
+
+// errors += (tmp_node->rrsets != NULL);
+
+ knot_node_free(&tmp_node, 0, 0);
+ }
+ return (errors == 0);
+}
+
+static const int KNOT_NODE_TEST_COUNT = 8;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_node_tests_count(int argc, char *argv[])
+{
+ return KNOT_NODE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_node_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 1;
+
+ res = test_node_create();
+ ok(res, "node: create");
+ res_final *= res;
+
+ skip(!res, 6)
+
+ ok((res = test_node_add_rrset()), "node: add");
+ res_final *= res;
+
+ ok((res = test_node_get_rrset()), "node: get");
+ res_final *= res;
+
+ ok((res = test_node_get_parent()), "node: get parent");
+ res_final *= res;
+
+ ok((res = test_node_set_parent()), "node: set parent");
+ res_final *= res;
+
+ ok((res = test_node_sorting()), "node: sort");
+ res_final *= res;
+
+ ok((res = test_node_free_rrsets()), "node: free rrsets");
+ res_final *= res;
+
+ endskip;
+
+ ok((res = test_node_delete()), "node: delete");
+ //res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/node_tests.h b/src/tests/libknot/libknot/node_tests.h
new file mode 100644
index 0000000..a90179f
--- /dev/null
+++ b/src/tests/libknot/libknot/node_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_NODE_TESTS_H_
+#define _KNOTD_NODE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api node_tests_api;
+
+#endif /* _KNOTD_NODE_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/nsec3_tests.c b/src/tests/libknot/libknot/nsec3_tests.c
new file mode 100644
index 0000000..7b95549
--- /dev/null
+++ b/src/tests/libknot/libknot/nsec3_tests.c
@@ -0,0 +1,252 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+
+#include "libknot/common.h"
+#include "libknot/util/error.h"
+#include "libknot/nsec3.h"
+#include "libknot/util/utils.h"
+#include "common/base32hex.h"
+#include "nsec3_tests.h"
+
+#ifdef TEST_WITH_LDNS
+#include "ldns/ldns.h"
+#endif
+
+static int knot_nsec3_tests_count(int argc, char *argv[]);
+static int knot_nsec3_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api nsec3_tests_api = {
+ "NSEC3", //! Unit name
+ &knot_nsec3_tests_count, //! Count scheduled tests
+ &knot_nsec3_tests_run //! Run scheduled tests
+};
+
+extern int compare_wires_simple(uint8_t *w1, uint8_t *w2, uint count);
+
+static int test_nsec3_params_from_wire()
+{
+ /* Create sample NSEC3PARAM rdata */
+ knot_rdata_item_t items[4];
+ knot_rdata_t *rdata = knot_rdata_new();
+ rdata->items = items;
+ rdata->count = 4;
+ knot_rdata_item_set_raw_data(rdata, 0, (uint16_t *)"\x1\x0\x1");
+ knot_rdata_item_set_raw_data(rdata, 1, (uint16_t *)"\x1\x0\x0");
+ knot_rdata_item_set_raw_data(rdata, 2, (uint16_t *)"\x2\x0\x0\x64");
+ knot_rdata_item_set_raw_data(rdata, 3,
+ (uint16_t *)"\xF\x0\xE\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF");
+
+ knot_rrset_t *rrset =
+ knot_rrset_new(knot_dname_new_from_str("cz.",
+ strlen("cz."), NULL),
+ KNOT_RRTYPE_NSEC3PARAM,
+ KNOT_CLASS_IN,
+ 3600);
+ assert(rrset);
+ int ret = knot_rrset_add_rdata(rrset, rdata);
+ assert(ret == KNOT_EOK);
+
+ knot_nsec3_params_t nsec3_test_params;
+
+ int errors = 0;
+ int lived = 0;
+ lives_ok({
+ /* Create special variable for this block. */
+ if (knot_nsec3_params_from_wire(NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_nsec3_params_from_wire(&nsec3_test_params, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_nsec3_params_from_wire(NULL, rrset) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+
+ }, "nsec3 params from wire NULL tests");
+ errors += lived != 1;
+
+ if (knot_nsec3_params_from_wire(&nsec3_test_params,
+ rrset) != KNOT_EOK) {
+ diag("Could not convert nsec3 params to wire!");
+ return 0;
+ }
+
+ if (nsec3_test_params.algorithm != 1) {
+ diag("Algorithm error");
+ errors++;
+ }
+
+ if (nsec3_test_params.flags != 0) {
+ diag("Flags error %d", nsec3_test_params.flags);
+ errors++;
+ }
+
+ if (nsec3_test_params.iterations != 100) {
+ diag("Iterations error %d", nsec3_test_params.iterations);
+ errors++;
+ }
+ printf("salt length: %d\n", nsec3_test_params.salt_length);
+
+ if (nsec3_test_params.salt_length != 14) {
+ diag("Salt length error %d", nsec3_test_params.salt_length);
+ return 0;
+ }
+
+ if (compare_wires_simple((uint8_t *)nsec3_test_params.salt,
+ (uint8_t *)"\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF\xF",
+ 14) != 0) {
+ diag("Salt wire error");
+ errors++;
+ }
+
+ knot_rrset_free(&rrset);
+ return (errors == 0);
+}
+
+static int test_nsec3_sha1()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_nsec3_params_t nsec3_test_params;
+
+ lives_ok({
+ if (knot_nsec3_sha1(NULL, NULL, 1, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_nsec3_sha1(&nsec3_test_params,
+ NULL, 1, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ uint8_t data[20];
+ lived = 1;
+ lived = 0;
+ if (knot_nsec3_sha1(&nsec3_test_params,
+ data, 20, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ uint8_t *digest = NULL;
+ lived = 1;
+ lived = 0;
+ if (knot_nsec3_sha1(&nsec3_test_params,
+ data, 20, &digest, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+// size_t size = 0;
+// lived = 1;
+// lived = 0;
+// if (knot_nsec3_sha1(&nsec3_test_params,
+// data, 20, &digest, &size) !=
+// KNOT_EBADARG) {
+// errors++;
+// }
+ lived = 1;
+ }, "NSEC3: nsec3 sha1 NULL tests");
+ if (errors) {
+ diag("Does not return KNOT_EBADARG after "
+ "execution with wrong arguments!");
+ }
+
+ errors += lived != 1;
+
+ uint8_t *digest = NULL;
+ size_t digest_size = 0;
+ if (knot_nsec3_sha1(&nsec3_test_params,
+ (uint8_t *)"\2ns\3nic\2cz",
+ strlen("\2ns\3nic\2cz"), &digest,
+ &digest_size) != KNOT_EOK) {
+ diag("Could not hash name!");
+ return 0;
+ }
+
+#ifdef TEST_WITH_LDNS
+ ldns_rdf *name = ldns_dname_new_frm_str("ns.nic.cz.");
+ assert(name);
+ ldns_rdf *hashed_name = ldns_nsec3_hash_name(name,
+ nsec3_test_params.algorithm,
+ nsec3_test_params.iterations,
+ nsec3_test_params.salt_length,
+ nsec3_test_params.salt);
+ assert(hashed_name);
+// knot_dname_t *dname_from_ldns =
+// knot_dname_new_from_wire(ldns_rdf_data(hashed_name),
+// ldns_rdf_size(hashed_name),
+// NULL);
+
+ char *name_b32 = NULL;
+ size_t size_b32 = base32hex_encode_alloc((char *)digest, digest_size,
+ &name_b32);
+
+// hex_print(name_b32, size_b32);
+// hex_print(ldns_rdf_data(hashed_name), ldns_rdf_size(hashed_name));
+ if (ldns_rdf_size(hashed_name) != size_b32) {
+ diag("Wrong hashed name length! Should be: %d is: %d",
+ ldns_rdf_size(hashed_name), size_b32);
+ return 0;
+ }
+
+ if (compare_wires_simple(ldns_rdf_data(hashed_name),
+ (uint8_t *)name_b32, size_b32) != 0) {
+ diag("Wrong hashed name wire!");
+ errors++;
+ }
+#endif
+
+#ifndef TEST_WITH_LDNS
+ diag("Warning: without ldns this test is only partial!");
+#endif
+ return (errors == 0);
+}
+
+static const int KNOT_NSEC3_TESTS_COUNT = 2;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_nsec3_tests_count(int argc, char *argv[])
+{
+ return KNOT_NSEC3_TESTS_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_nsec3_tests_run(int argc, char *argv[])
+{
+ ok(test_nsec3_params_from_wire(), "nsec3: params from wire");
+ ok(test_nsec3_sha1(), "nsec3: sha1");
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/nsec3_tests.h b/src/tests/libknot/libknot/nsec3_tests.h
new file mode 100644
index 0000000..10e7ed9
--- /dev/null
+++ b/src/tests/libknot/libknot/nsec3_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_NSEC3_TESTS_H_
+#define _KNOTD_NSEC3_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api nsec3_tests_api;
+
+#endif /* _KNOTD_NSEC3_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/packet_tests.c b/src/tests/libknot/libknot/packet_tests.c
new file mode 100644
index 0000000..185504f
--- /dev/null
+++ b/src/tests/libknot/libknot/packet_tests.c
@@ -0,0 +1,430 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "packet_tests.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/packet.h"
+#include "libknot/util/wire.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+
+static int packet_tests_count(int argc, char *argv[]);
+static int packet_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api packet_tests_api = {
+ "packet", //! Unit name
+ &packet_tests_count, //! Count scheduled tests
+ &packet_tests_run //! Run scheduled tests
+};
+
+static int test_packet_new()
+{
+ int errors = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ if (packet == NULL) {
+ diag("Could not create packet using prealloc_node constant!");
+ errors++;
+ }
+ knot_packet_free(&packet);
+
+ packet = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ if (packet == NULL) {
+ diag("Could not create packet using prealloc_query constant!");
+ errors++;
+ }
+ knot_packet_free(&packet);
+
+ packet = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ if (packet == NULL) {
+ diag("Could not create packet using prealloc_resp constant!");
+ errors++;
+ }
+ knot_packet_free(&packet);
+
+ /*!< \todo Should it create packet using any size? */
+
+ return (errors == 0);
+}
+
+static int test_packet_parse_from_wire()
+{
+ int errors = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+
+ int tmp = 0;
+ lives_ok({
+ if (knot_packet_parse_from_wire(NULL, NULL, 0, 0) !=
+ KNOT_EBADARG) {
+ diag("Trying to parse NULL packet with NULL wire "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ tmp = 1;
+ tmp = 0;
+ if (knot_packet_parse_from_wire(packet, NULL, 0, 0) !=
+ KNOT_EBADARG) {
+ diag("Trying to parse with NULL wire "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ tmp = 1;
+ tmp = 0;
+ if (knot_packet_parse_from_wire(packet, (uint8_t *)0xbeef,
+ 0, 0) !=
+ KNOT_EFEWDATA) {
+ diag("Trying to parse 0 lengt"
+ "did not return KNOT_EOK!");
+ errors++;
+ }
+ tmp = 1;
+ }, "packet: parse from wire NULL tests.");
+ errors += tmp != 1;
+
+ knot_packet_free(&packet);
+
+ return (errors == 0);
+}
+
+static int test_packet_parse_next_rr_answer()
+{
+ int errors = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ int tmp = 0;
+ lives_ok({
+ int ret = 0;
+ if (knot_packet_parse_next_rr_answer(NULL, NULL) !=
+ KNOT_EBADARG) {
+ diag("Trying to parse next RR answer with "
+ "NULL packet with and NULL RRSet "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ tmp = 1;
+ tmp = 0;
+ if ((ret = knot_packet_parse_next_rr_answer(packet,
+ NULL)) !=
+ KNOT_EBADARG) {
+ diag("Trying to parse next RR with NULL RRSet pointer "
+ "did not return KNOT_EBADARG! Got %d.",
+ ret);
+ errors++;
+ }
+ tmp = 1;
+// knot_rrset_t *rrset = (knot_rrset_t *)0xaaaa;
+// tmp = 0;
+// if (knot_packet_parse_next_rr_answer(packet,
+// &rrset) !=
+// KNOT_EBADARG) {
+// diag("Trying to parse next RR answer with rrset pointer"
+// " not pointing to NULL did not "
+// "return KNOT_EBADARG!");
+// errors++;
+// }
+// tmp = 1;
+ }, "packet: parse next rr answer NULL tests.");
+ errors += tmp != 1;
+
+ knot_packet_free(&packet);
+
+ return (errors == 0);
+}
+
+static int test_packet_parse_rest()
+{
+ int res = 0;
+ lives_ok({res = knot_packet_parse_rest(NULL);},
+ "packet: parse rest NULL test");
+
+ if (res != KNOT_EBADARG) {
+ diag("parse rest NULL did not return KNOT_EBADARG.\n");
+ return 1;
+ }
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ assert(packet);
+
+ todo();
+ lives_ok({res = knot_packet_parse_rest(packet);},
+ "packet: parser rest empty packet");
+ endtodo;
+
+ knot_packet_free(&packet);
+
+ return 1;
+}
+
+
+static int test_packet_set_max_size()
+{
+ int errors = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_NONE);
+ assert(packet);
+
+ int lived = 0;
+
+ lives_ok({
+ lived = 0;
+ if (knot_packet_set_max_size(NULL, 1) != KNOT_EBADARG) {
+ diag("Calling packet_set_max() with NULL packet "
+ "did not return KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+ }, "packet: set max size NULL test");
+
+ errors += lived != 1;
+
+ if (knot_packet_set_max_size(packet, 0) != KNOT_EBADARG) {
+ diag("Calling packet_set_max() with size eqeal to 0 did not "
+ "return KNOT_EBADARG");
+ errors++;
+ }
+
+ if (knot_packet_set_max_size(packet, 10) != KNOT_EOK) {
+ diag("Calling packet_set_max() with valid arguments did not "
+ "return KNOT_EOK");
+ errors++;
+ }
+
+ knot_packet_free(&packet);
+
+ return (errors == 0);
+}
+
+static int test_packet_add_tmp_rrset()
+{
+ int errors = 0;
+ int lived = 0;
+
+ /* knot_packet_add_tmp_rrset only works with pointers. */
+ knot_rrset_t *rrset = (knot_rrset_t *)0xabcdef;
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ lives_ok({
+ if (knot_packet_add_tmp_rrset(NULL, rrset) !=
+ KNOT_EBADARG) {
+ diag("Trying to add to NULL packet did not return "
+ "KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_packet_add_tmp_rrset(packet, NULL) !=
+ KNOT_EBADARG) {
+ diag("Trying to add NULL rrset did not return "
+ "KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_packet_add_tmp_rrset(NULL, NULL) !=
+ KNOT_EBADARG) {
+ diag("Trying to add NULL rrset to NULL packet "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "packet: add tmp rrset NULL test");
+ errors += lived != 1;
+
+ if (knot_packet_add_tmp_rrset(packet, rrset) != KNOT_EOK) {
+ diag("Could not add valid RRSet to packet!");
+ errors++;
+ }
+
+ /* Not freeing because RRSet is fake. */
+// knot_packet_free(&packet);
+
+ free(packet->wireformat);
+ free(packet);
+
+ return (errors == 0);
+}
+
+//static int test_packet_contains()
+//{
+// int errors = 0;
+// int lives = 0;
+
+// knot_packet_t *packet =
+// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+// assert(packet);
+
+// lives_ok({
+// if (knot_packet_contains(packet, NULL,
+// KNOT_RRSET_COMPARE_PTR) !=
+// KNOT_EBADARG{
+// diag();
+// }
+// }, "packet: contains NULL tests);
+
+// knot_packet_contains()
+
+//}
+
+static int test_packet_header_to_wire()
+{
+ int errors = 0;
+ int lived = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+ size_t size;
+
+ lives_ok({
+ knot_packet_header_to_wire(NULL, NULL, NULL);
+ lived = 1;
+ lived = 0;
+ knot_packet_header_to_wire(&packet->header, NULL, &size);
+ lived = 1;
+ }, "packet: header to wire NULL tests");
+ errors += lived != 1;
+
+ knot_packet_free(&packet);
+ return (errors == 0);
+}
+
+static int test_packet_question_to_wire()
+{
+ int errors = 0 ;
+ int lived = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ lives_ok({
+ if (knot_packet_question_to_wire(NULL) != KNOT_EBADARG) {
+ diag("Calling packet_question_to_wire with "
+ "NULL pointer did not result to KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "packet: question to wire NULL tests");
+ errors += lived != 1;
+
+ packet->size = KNOT_WIRE_HEADER_SIZE + 1;
+ if (knot_packet_question_to_wire(packet) != KNOT_ERROR) {
+ diag("Calling packet_question_to_wire with oversized packet "
+ "did not return KNOT_ERROR!");
+ errors++;
+ }
+
+ knot_packet_free(&packet);
+ return (errors == 0);
+}
+
+static int test_packet_edns_to_wire()
+{
+ int errors = 0 ;
+ int lived = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ lives_ok({
+ knot_packet_edns_to_wire(NULL);
+ lived = 1;
+ }, "packet: question to wire NULL tests");
+ errors += lived != 1;
+
+ knot_packet_free(&packet);
+ return (errors == 0);
+}
+
+static int test_packet_to_wire()
+{
+ int errors = 0 ;
+ int lived = 0;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+
+ lives_ok({
+ if (knot_packet_to_wire(NULL, NULL, NULL) != KNOT_EBADARG) {
+ diag("Calling packet_to_wire with "
+ "NULL pointers did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ size_t size;
+ lived = 0;
+ if (knot_packet_to_wire(packet, NULL, &size) !=
+ KNOT_EBADARG) {
+ diag("Calling packet_to_wire with "
+ "NULL wire did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ uint8_t *wire = (uint8_t *)0xabcdef;
+ lived = 0;
+ if (knot_packet_to_wire(packet, &wire, &size) !=
+ KNOT_EBADARG) {
+ diag("Calling packet_to_wire with "
+ "wire not pointing to NULL did not return"
+ " KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "packet: to wire NULL tests");
+ errors += lived != 1;
+
+ knot_packet_free(&packet);
+ return (errors == 0);
+}
+
+static const uint KNOT_PACKET_TEST_COUNT = 21;
+
+static int packet_tests_count(int argc, char *argv[])
+{
+ return KNOT_PACKET_TEST_COUNT;
+}
+
+static int packet_tests_run(int argc, char *argv[])
+{
+ int res = 0;
+ ok(res = test_packet_new(), "packet: new");
+ skip(!res, 20);
+ ok(test_packet_parse_rest(), "packet: parse rest");
+ ok(test_packet_parse_from_wire(), "packet: parse from wire");
+ ok(test_packet_parse_next_rr_answer(), "packet: parse next rr answer");
+ ok(test_packet_set_max_size(), "packet: set max size");
+ ok(test_packet_add_tmp_rrset(), "packet: add tmp rrset");
+ ok(test_packet_header_to_wire(), "packet: header to wire");
+ ok(test_packet_question_to_wire(), "packet: header to wire");
+ ok(test_packet_edns_to_wire(), "packet: header to wire");
+ ok(test_packet_to_wire(), "packet: to wire");
+// ok(res = test_packet_contains(), "Packet: contains");
+ endskip;
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/packet_tests.h b/src/tests/libknot/libknot/packet_tests.h
new file mode 100644
index 0000000..5a8ce03
--- /dev/null
+++ b/src/tests/libknot/libknot/packet_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_PACKET_TESTS_H_
+#define _KNOTD_PACKET_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api packet_tests_api;
+
+#endif /* _KNOTD_PACKET_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/query_tests.c b/src/tests/libknot/libknot/query_tests.c
new file mode 100644
index 0000000..1e4e081
--- /dev/null
+++ b/src/tests/libknot/libknot/query_tests.c
@@ -0,0 +1,160 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "packet_tests.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/packet.h"
+#include "libknot/util/wire.h"
+#include "libknot/packet/query.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+
+static int query_tests_count(int argc, char *argv[]);
+static int query_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api query_tests_api = {
+ "query", //! Unit name
+ &query_tests_count, //! Count scheduled tests
+ &query_tests_run //! Run scheduled tests
+};
+
+static const uint KNOT_QUERY_TEST_COUNT = 1;
+
+static int query_tests_count(int argc, char *argv[])
+{
+ return KNOT_QUERY_TEST_COUNT;
+}
+
+static int test_query_init()
+{
+ int errors = 0;
+ int lived = 0;
+ knot_packet_t *query =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ assert(query);
+ lives_ok({
+ if (knot_query_init(NULL) != KNOT_EBADARG) {
+ diag("Calling query_init with NULL query did "
+ "not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "query: init NULL tests");
+ errors += lived != 1;
+
+ assert(knot_packet_set_max_size(query, 1024 * 10) == KNOT_EOK);
+ if (knot_query_init(query) != KNOT_EOK) {
+ diag("Calling query_init with valid query did not return "
+ "KNOT_EOK!");
+ errors++;
+ }
+
+ if (!knot_packet_is_query(query)) {
+ diag("QR flag was not set!");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_query_set_question()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_packet_t *query =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ assert(query);
+ assert(knot_packet_set_max_size(query, 1024 * 10) == KNOT_EOK);
+ knot_query_init(query);
+
+ knot_rrset_t *rrset =
+ knot_rrset_new(knot_dname_new_from_str("a.ns.cz.",
+ strlen("a.ns.cz."),
+ NULL),
+ KNOT_RRTYPE_A, KNOT_CLASS_IN, 3600);
+ assert(rrset);
+
+ knot_question_t *question = malloc(sizeof(knot_question_t));
+ assert(question);
+ question->qname = rrset->owner;
+ question->qtype = rrset->type;
+ question->qclass = rrset->rclass;
+
+ lives_ok({
+ if (knot_query_set_question(NULL, NULL) != KNOT_EBADARG) {
+ diag("Calling query_set_question with NULL");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_query_set_question(query, NULL) != KNOT_EBADARG) {
+ diag("Calling query_set_question with NULL");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_query_set_question(NULL, question) != KNOT_EBADARG) {
+ diag("Calling query_set_question with NULL");
+ errors++;
+ }
+ lived = 1;
+ }, "query: set question NULL tests");
+ errors += lived != 1;
+
+ if (knot_query_set_question(query, question) != KNOT_EOK) {
+ diag("Calling query_set_question with valid arguments ");
+ errors++;
+ }
+
+ if (query->question.qname != rrset->owner) {
+ diag("Qname was not set right!");
+ errors++;
+ }
+
+ if (query->question.qtype != rrset->type) {
+ diag("Qtype was not set right!");
+ errors++;
+ }
+
+ if (query->question.qclass != rrset->rclass) {
+ diag("Qclass was not set right!");
+ errors++;
+ }
+
+ if (query->header.qdcount != 1) {
+ diag("Qdcount was not set right!");
+ errors++;
+ }
+
+ knot_packet_free(&query);
+ knot_rrset_deep_free(&rrset, 1, 0, 0);
+
+ return (errors == 0);
+}
+
+static int query_tests_run(int argc, char *argv[])
+{
+ ok(test_query_init(), "query: init");
+ ok(test_query_set_question(), "query: set question");
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/query_tests.h b/src/tests/libknot/libknot/query_tests.h
new file mode 100644
index 0000000..037ecab
--- /dev/null
+++ b/src/tests/libknot/libknot/query_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_QUERY_TESTS_H_
+#define _KNOTD_QUERY_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api query_tests_api;
+
+#endif /* _KNOTD_QUERY_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/rdata_tests.c b/src/tests/libknot/libknot/rdata_tests.c
new file mode 100644
index 0000000..561686a
--- /dev/null
+++ b/src/tests/libknot/libknot/rdata_tests.c
@@ -0,0 +1,954 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "tests/libknot/libknot/rdata_tests.h"
+#include "libknot/common.h"
+#include "libknot/rdata.h"
+#include "libknot/dname.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/util/utils.h"
+#include "libknot/util/error.h"
+
+enum { TEST_DOMAINS_OK = 8 };
+
+struct test_domain {
+ char *str;
+ char *wire;
+ uint size;
+ char *labels;
+ short label_count;
+};
+
+/*! \warning Do not change the order in those, if you want to test some other
+ * feature with new dname, add it at the end of these arrays.
+ */
+static const struct test_domain
+ test_domains_ok[TEST_DOMAINS_OK] = {
+ { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "test.domain.com.", "\4test\6domain\3com", 17,
+ "\x0\x5\xC", 3 },
+ { ".", "\0", 1,
+ "", 0 },
+ { "foo.bar.net.", "\3foo\3bar\3net", 13,
+ "\x0\x4\x8", 3},
+ { "bar.net.", "\3bar\3net", 9,
+ "\x0\x4", 2}
+};
+
+
+static int knot_rdata_tests_count(int argc, char *argv[]);
+static int knot_rdata_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api rdata_tests_api = {
+ "DNS library - rdata", //! Unit name
+ &knot_rdata_tests_count, //! Count scheduled tests
+ &knot_rdata_tests_run //! Run scheduled tests
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Unit implementation.
+ */
+
+static uint16_t *RDATA_ITEM_PTR = (uint16_t *)0xDEADBEEF;
+
+enum { RDATA_ITEMS_COUNT = 7, TEST_RDATA_COUNT = 4 , RDATA_DNAMES_COUNT = 2 };
+
+static knot_dname_t RDATA_DNAMES[RDATA_DNAMES_COUNT] = {
+ {{}, (uint8_t *)"\6abcdef\7example\3com", 20,
+ (uint8_t *)"\x0\x7\xF", 3},
+ {{}, (uint8_t *)"\6abcdef\3foo\3com", 16,
+ (uint8_t *)"\x0\x7\xB", 3}
+};
+
+static knot_rdata_item_t TEST_RDATA_ITEMS[RDATA_ITEMS_COUNT] = {
+ {.dname = (knot_dname_t *)0xF00},
+ {.raw_data = (uint16_t *)"some data"},
+ {.raw_data = (uint16_t *)"other data"},
+ {.raw_data = (uint16_t *)"123456"},
+ {.raw_data = (uint16_t *)"654321"},
+ {.dname = &RDATA_DNAMES[0]},
+ {.dname = &RDATA_DNAMES[1]}
+};
+
+/* \note indices 0 to 3 should not be changed - used in (and only in)
+ * test_rdata_compare() - better than creating new struct just for this
+ */
+static knot_rdata_t test_rdata[TEST_RDATA_COUNT] = {
+ {&TEST_RDATA_ITEMS[3], 1, &test_rdata[1]},
+ {&TEST_RDATA_ITEMS[4], 1, &test_rdata[2]},
+ {&TEST_RDATA_ITEMS[5], 1, &test_rdata[3]},
+ {&TEST_RDATA_ITEMS[6], 1, &test_rdata[4]},
+};
+
+static knot_rdata_t TEST_RDATA = {
+ &TEST_RDATA_ITEMS[0],
+ 3,
+ &TEST_RDATA
+};
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_new().
+ *
+ * Creates new RDATA structure with no items and tests if there really are no
+ * items in it.
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_create()
+{
+ knot_rdata_t *rdata = knot_rdata_new();
+ if (rdata == NULL) {
+ diag("RDATA structure not created!");
+ return 0;
+ }
+
+ if (knot_rdata_item(rdata, 0) != NULL) {
+ diag("Get item returned something else than NULL!");
+ knot_rdata_free(&rdata);
+ return 0;
+ }
+
+ knot_rdata_free(&rdata);
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_free().
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_delete()
+{
+ // how to test this??
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void generate_rdata(uint8_t *data, int size)
+{
+ for (int i = 0; i < size; ++i) {
+ data[i] = rand() % 256;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int fill_rdata(uint8_t *data, int max_size, uint16_t rrtype,
+ knot_rdata_t *rdata)
+{
+ assert(rdata != NULL);
+ assert(data != NULL);
+ assert(max_size > 0);
+
+ uint8_t *pos = data;
+ int used = 0;
+ int wire_size = 0;
+
+ //note("Filling RRType %u", rrtype);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype);
+
+ uint item_count = desc->length;
+ knot_rdata_item_t *items =
+ (knot_rdata_item_t *)malloc(item_count
+ * sizeof(knot_rdata_item_t));
+
+ for (int i = 0; i < item_count; ++i) {
+ uint size = 0;
+ int domain = 0;
+ knot_dname_t *dname = NULL;
+ int binary = 0;
+ int stored_size = 0;
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[0].wire,
+ test_domains_ok[0].size, NULL);
+ assert(dname != NULL);
+ /* note("Created domain name: %s",
+ knot_dname_name(dname)); */
+ //note("Domain name ptr: %p", dname);
+ domain = 1;
+ size = knot_dname_size(dname);
+ //note("Size of created domain name: %u", size);
+ assert(size < KNOT_MAX_RDATA_ITEM_SIZE);
+ // store size of the domain name
+ *(pos++) = size;
+ // copy the domain name
+ memcpy(pos, knot_dname_name(dname), size);
+ pos += size;
+ break;
+ default:
+ binary = 1;
+ size = rand() % KNOT_MAX_RDATA_ITEM_SIZE;
+ }
+
+ if (binary) {
+ // Rewrite the actual 2 bytes in the data array
+ // with length.
+ // (this is a bit ugly, but does the work ;-)
+ knot_wire_write_u16(pos, size);
+ //*pos = size;
+ }
+
+ //note("Filling %u bytes", size);
+ used += size;
+ assert(used < max_size);
+
+ if (domain) {
+ items[i].dname = dname;
+ wire_size += knot_dname_size(dname);
+/* note("Saved domain name ptr on index %d: %p",
+ i, items[i].dname); */
+ } else {
+ free(dname);
+// note("Saved raw data ptr on index %d: %p",i, pos);
+ items[i].raw_data = (uint16_t *)pos;
+ pos += size;
+ wire_size += size;
+ if (binary && !stored_size) {
+ wire_size -= 2;
+ }
+ }
+ }
+
+ int res = knot_rdata_set_items(rdata, items, item_count);
+ if (res != 0) {
+ diag("knot_rdata_set_items() returned %d.", res);
+ free(items);
+ return -1;
+ } else {
+ free(items);
+ return wire_size;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Checks if all RDATA items in the given RDATA structure are correct.
+ *
+ * \return Number of errors encountered. Error is either if some RDATA item
+ * is not set (i.e. NULL) or if it has other than the expected value.
+ */
+static int check_rdata(const uint8_t *data, int max_size, uint16_t rrtype,
+ const knot_rdata_t *rdata)
+{
+ assert(rdata != NULL);
+ assert(data != NULL);
+ assert(max_size > 0);
+
+ int errors = 0;
+
+ const uint8_t *pos = data;
+ int used = 0;
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype);
+ uint item_count = desc->length;
+ //note("check_rdata(), RRType: %u", rrtype);
+ //note(" item count: %u", item_count);
+
+ for (int i = 0; i < item_count; ++i) {
+ uint size = 0;
+ int domain = 0;
+ int binary = 0;
+
+ //note(" item: %d", i);
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ //note(" domain name");
+ domain = 1;
+ size = knot_dname_size(knot_rdata_item(
+ rdata, i)->dname);
+ break;
+ default:
+ size =
+ knot_wire_read_u16((uint8_t *)
+ (knot_rdata_item(
+ rdata, i)->raw_data));
+ }
+
+ assert(size > 0);
+ //note("Size: %u", size);
+ used += size;
+ assert(used < max_size);
+
+ //note(" item size: %u", size);
+
+ if (domain) {
+ /*note("Domain name ptr: %p",
+ knot_rdata_get_item(rdata, i)->dname);*/
+ // check dname size
+ if (*pos != size) {
+ diag("Domain name stored in %d-th"
+ "RDATA has wrong size: %d"
+ " (should be %d)", size, *pos);
+ ++errors;
+ } else if (strncmp((char *)knot_dname_name(
+ knot_rdata_item(rdata, i)->dname),
+ (char *)(pos + 1), *pos) != 0) {
+ diag("Domain name stored in %d-th"
+ "RDATA item is wrong: %s ("
+ "should be %.*s)", i,
+ knot_dname_name(knot_rdata_item(
+ rdata, i)->dname),
+ *pos, (char *)(pos + 1));
+ ++errors;
+ }
+
+ pos += *pos + 1;
+
+ continue;
+ }
+
+ if (binary &&
+ size !=
+ knot_wire_read_u16(
+ (uint8_t *)(knot_rdata_item(rdata, i)->raw_data))) {
+ diag("Size of stored binary data is wrong:"
+ " %u (should be %u)",
+ knot_rdata_item(rdata, i)->raw_data[0] + 1,
+ size);
+ ++errors;
+ }
+
+ if (strncmp((char *)
+ (&knot_rdata_item(rdata, i)->raw_data[0]),
+ (char *)pos, size) != 0) {
+/* knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype); */
+
+ diag("Data stored in %d-th RDATA item are wrong.", i);
+ ++errors;
+ }
+
+ pos += size;
+ }
+
+ return errors;
+}
+
+/*----------------------------------------------------------------------------*/
+
+//static int convert_to_wire(const uint8_t *data, int max_size, uint16_t rrtype,
+// uint8_t *data_wire)
+//{
+// //note("Converting type %u", rrtype);
+
+// int wire_size = 0;
+// const uint8_t *pos = data;
+// uint8_t *pos_wire = data_wire;
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(rrtype);
+// uint item_count = desc->length;
+
+// for (int i = 0; i < item_count; ++i) {
+// const uint8_t *from = NULL;
+// uint to_copy = 0;
+
+// switch (desc->wireformat[i]) {
+// case KNOT_RDATA_WF_COMPRESSED_DNAME:
+// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+// case KNOT_RDATA_WF_LITERAL_DNAME:
+// // copy the domain name without its length
+// from = pos + 1;
+// to_copy = *pos;
+// pos += *pos + 1;
+///* note("Domain name in wire format (size %u): %s",
+// to_copy, (char *)from); */
+// break;
+// case KNOT_RDATA_WF_BYTE:
+// //note(" 1byte int");
+// from = pos;
+// to_copy = 1;
+// pos += 1;
+// break;
+// case KNOT_RDATA_WF_SHORT:
+// //note(" 2byte int");
+// from = pos;
+// to_copy = 2;
+// pos += 2;
+// break;
+// case KNOT_RDATA_WF_LONG:
+// //note(" 4byte int");
+// from = pos;
+// to_copy = 4;
+// pos += 4;
+// break;
+// case KNOT_RDATA_WF_A:
+// //note(" A");
+// from = pos;
+// to_copy = 4;
+// pos += 4;
+// break;
+// case KNOT_RDATA_WF_AAAA:
+// //note(" AAAA");
+// from = pos;
+// to_copy = 16;
+// pos += 16;
+// break;
+// case KNOT_RDATA_WF_BINARY:
+// case KNOT_RDATA_WF_APL: // saved as binary
+// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary
+// //note(" binary");
+// from = pos + 1;
+// to_copy = *pos;
+// pos += *pos + 1;
+// break;
+// case KNOT_RDATA_WF_TEXT:
+// case KNOT_RDATA_WF_BINARYWITHLENGTH:
+// //note(" text or binary with length (%u)", *pos);
+// to_copy = *pos + 1;
+// from = pos;
+// pos += *pos + 1;
+// break;
+// default:
+// assert(0);
+// }
+
+// //note("Copying %u bytes from %p", to_copy, from);
+
+// assert(from != NULL);
+// assert(to_copy != 0);
+
+// memcpy(pos_wire, from, to_copy);
+// pos_wire += to_copy;
+// wire_size += to_copy;
+
+// assert(wire_size < max_size);
+// }
+
+// return wire_size;
+//}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_set_item().
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_set_item()
+{
+ knot_rdata_t *rdata = knot_rdata_new();
+ knot_rdata_item_t item;
+ item.raw_data = RDATA_ITEM_PTR;
+
+ int ret = knot_rdata_set_item(rdata, 0, item);
+ if (ret == 0) {
+ diag("knot_rdata_set_item() called on empty RDATA"
+ "returned %d instead of error (-1).", ret);
+ knot_rdata_free(&rdata);
+ return 0;
+ }
+
+// uint8_t *data = malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE);
+// assert(data);
+ uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+ generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+ // set items through set_items() and then call set_item()
+ uint16_t rrtype = rand() % KNOT_RRTYPE_LAST + 1;
+ if (fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, rrtype, rdata) < 0) {
+ knot_rdata_free(&rdata);
+ diag("Error filling RDATA");
+ return 0;
+ }
+
+ uint8_t pos = rand() % knot_rrtype_descriptor_by_type(rrtype)->length;
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype);
+
+ // if the rdata on this position is domain name, free it to avoid leaks
+ if (desc->wireformat[pos] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME
+ || desc->wireformat[pos] == KNOT_RDATA_WF_COMPRESSED_DNAME
+ || desc->wireformat[pos] == KNOT_RDATA_WF_LITERAL_DNAME) {
+ knot_dname_free(&(rdata->items[pos].dname));
+ }
+
+ ret = knot_rdata_set_item(rdata, pos, item);
+ if (ret != 0) {
+ diag("knot_rdata_set_item() called on filled"
+ " RDATA returned %d instead of 0.", ret);
+ knot_rdata_free(&rdata);
+ return 0;
+ }
+
+ if (knot_rdata_item(rdata, pos)->raw_data != RDATA_ITEM_PTR) {
+ diag("RDATA item on position %d is wrong: %p (should be %p).",
+ pos, knot_rdata_item(rdata, pos)->raw_data,
+ RDATA_ITEM_PTR);
+ knot_rdata_free(&rdata);
+ return 0;
+ }
+
+ for (int x = 0; x < desc->length; x++) {
+ if (x != pos && (
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_LITERAL_DNAME)) {
+ knot_dname_free(&(rdata->items[x].dname));
+ }
+ }
+
+// knot_rdata_free(&rdata);
+ return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_set_items().
+ *
+ * Iterates over the test_rdatas array and for each testing RDATA it creates
+ * the RDATA structure, sets its items (\see set_rdata_all()) and checks if the
+ * items are set properly (\see check_rdata()).
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_set_items()
+{
+ knot_rdata_t *rdata = NULL;
+ knot_rdata_item_t *item = (knot_rdata_item_t *)0xDEADBEEF;
+ int errors = 0;
+
+ // check error return values
+ if (knot_rdata_set_items(rdata, NULL, 0) != KNOT_EBADARG) {
+ diag("Return value of knot_rdata_set_items() "
+ "when rdata == NULL is wrong");
+ return 0;
+ } else {
+ rdata = knot_rdata_new();
+ assert(rdata != NULL);
+
+ if (knot_rdata_set_items(rdata, NULL, 0) != KNOT_EBADARG) {
+ diag("Return value of knot_rdata_set_items()"
+ " when items == NULL is wrong");
+// knot_rdata_free(&rdata);
+ return 0;
+ } else if (knot_rdata_set_items(rdata, item, 0) !=
+ KNOT_EBADARG) {
+ diag("Return value of knot_rdata_set_items()"
+ " when count == 0"
+ "is wrong");
+// knot_rdata_free(&rdata);
+ return 0;
+ }
+// knot_rdata_free(&rdata);
+ }
+
+ // generate some random data
+// uint8_t *data = malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE);
+ uint8_t data [KNOT_MAX_RDATA_WIRE_SIZE];
+ generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+ for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) {
+ rdata = knot_rdata_new();
+
+ if (fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata)
+ < 0) {
+ ++errors;
+ }
+ errors += check_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i,
+ rdata);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(i);
+
+ for (int x = 0; x < desc->length; x++) {
+ if (desc->wireformat[x] ==
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[x] ==
+ KNOT_RDATA_WF_LITERAL_DNAME) {
+// printf("freeing %p\n", rdata->items[x].dname);
+ knot_dname_free(&(rdata->items[x].dname));
+ }
+ }
+
+// knot_rdata_free(&rdata);
+ }
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_get_item().
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_get_item()
+{
+ const knot_rdata_t *rdata = &TEST_RDATA;
+
+ if (knot_rdata_item(rdata, TEST_RDATA.count) != NULL) {
+ diag("knot_rdata_get_item() called with"
+ "invalid position did not return NULL");
+ return 0;
+ }
+
+ int errors = 0;
+ if ((knot_rdata_item(rdata, 0)->dname)
+ != TEST_RDATA.items[0].dname) {
+ diag("RDATA item on position 0 is wrong: %p (should be %p)",
+ knot_rdata_item(rdata, 0), TEST_RDATA.items[0]);
+ ++errors;
+ }
+ if ((knot_rdata_item(rdata, 1)->raw_data)
+ != TEST_RDATA.items[1].raw_data) {
+ diag("RDATA item on position 0 is wrong: %p (should be %p)",
+ knot_rdata_item(rdata, 1), TEST_RDATA.items[1]);
+ ++errors;
+ }
+ if ((knot_rdata_item(rdata, 2)->raw_data)
+ != TEST_RDATA.items[2].raw_data) {
+ diag("RDATA item on position 0 is wrong: %p (should be %p)",
+ knot_rdata_item(rdata, 2), TEST_RDATA.items[2]);
+ ++errors;
+ }
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int test_rdata_compare()
+{
+ int errors = 0;
+
+ uint8_t format_rawdata = KNOT_RDATA_WF_BINARY;
+
+ uint8_t format_dname = KNOT_RDATA_WF_LITERAL_DNAME;
+
+ /* 123456 \w 654321 -> result -1 */
+ if (knot_rdata_compare(&test_rdata[0],
+ &test_rdata[1],
+ &format_rawdata) != -1) {
+ diag("RDATA raw data comparison failed 0");
+ errors++;
+ }
+
+ /* 123456 \w 123456 -> result 0 */
+ if (knot_rdata_compare(&test_rdata[0],
+ &test_rdata[0],
+ &format_rawdata) != 0) {
+ diag("RDATA raw data comparison failed 1 ");
+ errors++;
+ }
+
+ /* 123456 \w 654321 -> result 1 */
+ if (knot_rdata_compare(&test_rdata[1],
+ &test_rdata[0],
+ &format_rawdata) != 1) {
+ diag("RDATA raw data comparison failed 2");
+ errors++;
+ }
+
+ /* abcdef.example.com. \w abcdef.foo.com. -> result -1 */
+ int ret = 0;
+ if ((ret = knot_rdata_compare(&test_rdata[2],
+ &test_rdata[3],
+ &format_dname)) >= 0) {
+ diag("RDATA dname comparison failed 3");
+ errors++;
+ }
+
+ /* abcdef.example.com. \w abcdef.example.com. -> result 0 */
+ if (knot_rdata_compare(&test_rdata[2],
+ &test_rdata[2],
+ &format_dname) != 0) {
+ diag("RDATA dname comparison failed 4");
+ errors++;
+ }
+
+ /* abcdef.example.com. \w abcdef.foo.com -> result 1 */
+ if (knot_rdata_compare(&test_rdata[3],
+ &test_rdata[2],
+ &format_dname) != 1) {
+ diag("RDATA dname comparison failed 5");
+ errors++;
+ }
+
+
+
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+//static int test_rdata_wire_size()
+//{
+// knot_rdata_t *rdata;
+// int errors = 0;
+
+// // generate some random data
+// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) {
+// rdata = knot_rdata_new();
+
+// int size =
+// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata);
+
+// if (size < 0) {
+// ++errors;
+// } else {
+// int counted_size = knot_rdata_wire_size(rdata,
+// knot_rrtype_descriptor_by_type(i)->wireformat);
+// if (size != counted_size) {
+// diag("Wrong wire size computed (type %d):"
+// " %d (should be %d)",
+// i, counted_size, size);
+// ++errors;
+// }
+// }
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(i);
+
+// for (int x = 0; x < desc->length; x++) {
+// if (desc->wireformat[x] ==
+// KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_COMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_LITERAL_DNAME) {
+// knot_dname_free(&(rdata->items[x].dname));
+// }
+// }
+// knot_rdata_free(&rdata);
+// }
+
+// return (errors == 0);
+//}
+
+/*----------------------------------------------------------------------------*/
+
+//static int test_rdata_to_wire()
+//{
+// knot_rdata_t *rdata;
+// int errors = 0;
+
+// // generate some random data
+// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+// uint8_t data_wire[KNOT_MAX_RDATA_WIRE_SIZE];
+// uint8_t rdata_wire[KNOT_MAX_RDATA_WIRE_SIZE];
+// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) {
+// rdata = knot_rdata_new();
+
+// int size =
+// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata);
+
+// int size_expected =
+// convert_to_wire(data, KNOT_MAX_RDATA_WIRE_SIZE, i,
+// data_wire);
+
+// if (size < 0) {
+// ++errors;
+// } else {
+// if (size != size_expected) {
+// diag("Wire format size (%u) not"
+// " as expected (%u)",
+// size, size_expected);
+// ++errors;
+// } else {
+// if (knot_rdata_to_wire(rdata,
+// knot_rrtype_descriptor_by_type(i)->
+// wireformat, rdata_wire,
+// KNOT_MAX_RDATA_WIRE_SIZE) != 0) {
+// diag("Error while converting RDATA"
+// " to wire format.");
+// ++errors;
+// } else {
+// if (strncmp((char *)data_wire,
+// (char *)rdata_wire, size)
+// != 0) {
+// diag("RDATA converted to wire"
+// "format does not match"
+// " the expected value");
+// ++errors;
+// }
+// }
+// }
+// }
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(i);
+
+// for (int x = 0; x < desc->length; x++) {
+// if (desc->wireformat[x] ==
+// KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_COMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_LITERAL_DNAME) {
+// knot_dname_free(&(rdata->items[x].dname));
+// }
+// }
+// knot_rdata_free(&rdata);
+// }
+
+// return (errors == 0);
+//}
+
+static int test_rdata_free()
+{
+ return 0;
+// knot_rdata_t *tmp_rdata;
+
+// tmp_rdata = knot_rdata_new();
+
+// knot_rdata_free(&tmp_rdata);
+
+// return (tmp_rdata == NULL);
+}
+/* Can't test this with current implementation
+ * would be trying to free pointers on stack */
+static int test_rdata_deep_free()
+{
+ return 0;
+
+/* int errors = 0;
+
+ knot_rdata_t *tmp_rdata;
+
+ uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+
+ for (int i = 0; i <= KNOT_RRTYPE_LAST; i++) {
+ tmp_rdata = knot_rdata_new();
+
+ fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, tmp_rdata);
+
+ knot_rdata_deep_free(&tmp_rdata, i, 0);
+ errors += (tmp_rdata != NULL);
+ }
+
+ return (errors == 0); */
+}
+
+/*----------------------------------------------------------------------------*/
+
+static const int KNOT_RDATA_TEST_COUNT = 8;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_rdata_tests_count(int argc, char *argv[])
+{
+ return KNOT_RDATA_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_rdata_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 1;
+
+ res = test_rdata_create();
+ ok(res, "rdata: create empty");
+ res_final *= res;
+
+ skip(!res, 6);
+
+ todo();
+
+ ok(res = test_rdata_delete(), "rdata: delete");
+ //res_final *= res;
+
+ endtodo;
+
+ ok(res = test_rdata_get_item(), "rdata: get item");
+ res_final *= res;
+
+ skip(!res, 4)
+
+ ok(res = test_rdata_set_items(), "rdata: set items all at once");
+ res_final *= res;
+
+ skip(!res, 3);
+
+ ok(res = test_rdata_set_item(), "rdata: set items one-by-one");
+ res_final *= res;
+
+ ok(res = test_rdata_compare(), "rdata: compare");
+ res_final *= res;
+
+// ok(res = test_rdata_wire_size(), "rdata: wire size");
+// res_final *= res;
+
+// skip(!res, 1);
+
+// ok(res = test_rdata_to_wire(), "rdata: to wire");
+// res_final *= res;
+
+// endskip; /* test_rdata_wire_size() failed */
+
+ endskip; /* test_rdata_set_items() failed */
+
+ endskip; /* test_rdata_get_item() failed */
+
+ endskip; /* test_rdata_create() failed */
+
+ todo();
+
+ ok(res = test_rdata_deep_free(), "rdata: deep free");
+ res_final *= res;
+
+ ok(res = test_rdata_free(), "rdata: free");
+ res_final *= res;
+
+ endtodo;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/rdata_tests.h b/src/tests/libknot/libknot/rdata_tests.h
new file mode 100644
index 0000000..1f43c91
--- /dev/null
+++ b/src/tests/libknot/libknot/rdata_tests.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file rdata_tests.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * Contains unit tests for RDATA (knot_rdata_t) and RDATA item
+ * (knot_rdata_item_t) structures.
+ *
+ * Contains tests for:
+ * - creating empty RDATA structure with or without reserved space.
+ * - setting RDATA items one-by-one
+ * - setting RDATA items all at once
+ *
+ * As for now, the tests use several (TEST_RDATAS) RDATA structures, each
+ * with different number of RDATA items (given by test_rdatas). These are all
+ * initialized to pointers derived from RDATA_ITEM_PTR (first is RDATA_ITEM_PTR,
+ * second RDATA_ITEM_PTR + 1, etc.). The functions only test if the pointer
+ * is set properly.
+ *
+ * \todo It may be better to test also some RDATAs with predefined contents,
+ * such as some numbers, some domain name, etc. For this purpose, we'd
+ * need RDATA descriptors (telling the types of each RDATA item within an
+ * RDATA).
+ *
+ * \todo It will be fine to test all possible output values of all functions,
+ * e.g. test whether knot_rdata_get_item() returns NULL when passed an
+ * illegal position, etc.
+ */
+#ifndef _KNOTD_RDATA_TESTS_H_
+#define _KNOTD_RDATA_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api rdata_tests_api;
+
+#endif /* _KNOTD_RDATA_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/response_tests.c b/src/tests/libknot/libknot/response_tests.c
new file mode 100644
index 0000000..93cf2df
--- /dev/null
+++ b/src/tests/libknot/libknot/response_tests.c
@@ -0,0 +1,450 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+
+//#define RESP_TEST_DEBUG
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "tests/libknot/libknot/response_tests.h"
+#include "common/lists.h"
+#include "libknot/common.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/response.h"
+#include "libknot/rdata.h"
+#include "libknot/rrset.h"
+#include "libknot/dname.h"
+#include "libknot/util/wire.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/edns.h"
+
+#ifdef TEST_WITH_LDNS
+#include "ldns/ldns.h"
+#endif
+
+static int knot_response_tests_count(int argc, char *argv[]);
+static int knot_response_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api response_tests_api = {
+ "DNS library - response", //! Unit name
+ &knot_response_tests_count, //! Count scheduled tests
+ &knot_response_tests_run //! Run scheduled tests
+};
+
+static int test_response_init()
+{
+ int errors = 0;
+ int lived = 0;
+ lives_ok({
+ if (knot_response_init(NULL) != KNOT_EBADARG) {
+ diag("Calling response_init with NULL packet did "
+ "not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "response: init NULL tests");
+ errors += lived != 1;
+
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ assert(response);
+ response->max_size = KNOT_WIRE_HEADER_SIZE - 1;
+ if (knot_response_init(response) != KNOT_ESPACE) {
+ diag("Calling response_init too small packet did "
+ "not return KNOT_ESPACE!");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_response_init_query()
+{
+ int errors = 0;
+ int lived = 0;
+ lives_ok({
+ if (knot_response_init_from_query(NULL, NULL) !=
+ KNOT_EBADARG) {
+ diag("Calling response_init_query with NULL packet and "
+ "NULL query did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ knot_packet_set_max_size(response,
+ KNOT_PACKET_PREALLOC_RESPONSE);
+ knot_response_init(response);
+ lived = 0;
+ if (knot_response_init_from_query(response, NULL) !=
+ KNOT_EBADARG) {
+ diag("Calling response_init_query with NULL query "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_t *query =
+ knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
+ if (knot_response_init_from_query(NULL, query) !=
+ KNOT_EBADARG) {
+ diag("Calling response_init_query with NULL response "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ }, "response: init from query NULL tests");
+ errors += lived != 1;
+
+ /* Cannot test the rest of return values, since there is now constant
+ * controlling value that could return KNOT_EDNAMEPTR */
+
+ return (errors == 0);
+}
+
+int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count)
+{
+ int i = 0;
+ while (i < count &&
+ wire1[i] == wire2[i]) {
+ i++;
+ }
+ return (!(count == i));
+}
+
+
+//static int test_response_clear()
+//{
+// int errors = 0;
+// int lived = 0;
+// lives_ok({
+// knot_response_clear(NULL, 1);
+// lived = 1;
+// }, "response: clear NULL tests");
+// errors += lived != 1;
+
+// /*
+// * Create new response, convert to wire, then add something, clear
+// * the response, convert to wire again and compare wires.
+// */
+
+// knot_packet_t *response =
+// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+// knot_packet_set_max_size(response, KNOT_WIRE_HEADER_SIZE * 100);
+// assert(knot_response_init(response) == KNOT_EOK);
+
+// uint8_t *original_wire = NULL;
+// size_t original_size = 0;
+// assert(knot_packet_to_wire(response, &original_wire,
+// &original_size) ==
+// KNOT_EOK);
+// /* Do something in question section. */
+//// test_dname_t test_dname;
+//// test_dname.str = "ns8.nic.cz.";
+//// knot_dname_t *dname = dname_from_test_dname_str(&test_dname);
+//// assert(dname);
+
+// response->question.qtype = KNOT_RRTYPE_HINFO;
+// response->question.qclass = KNOT_CLASS_CH;
+
+// uint8_t *question_changed_wire = NULL;
+// size_t question_changed_size = 0;
+// assert(knot_packet_to_wire(response,
+// &question_changed_wire,
+// &question_changed_size) ==
+// KNOT_EOK);
+
+// knot_response_set_aa(response);
+// knot_response_set_tc(response);
+// knot_response_set_rcode(response, knot_quick_rand());
+
+// knot_response_clear(response, 0);
+// uint8_t *new_wire = NULL;
+// size_t new_size = 0;
+// assert(knot_packet_to_wire(response, &new_wire, &new_size) ==
+// KNOT_EOK);
+// if (question_changed_size != new_size) {
+// diag("Wrong wire size after calling response_clear! "
+// "got %d should be %d", new_size, question_changed_size);
+// errors++;
+// } else {
+// if (compare_wires_simple(question_changed_wire,
+// new_wire, new_size)) {
+// diag("Wrong wire after calling response_clear! ");
+// errors++;
+// }
+// }
+// free(new_wire);
+
+// new_wire = NULL;
+// new_size = 0;
+
+// /*!< \todo figure out this segfault! */
+
+//// knot_response_clear(response, 1);
+//// assert(knot_packet_to_wire(response, &new_wire, &new_size) ==
+//// KNOT_EOK);
+
+//// if (original_size != new_size) {
+//// diag("Wrong wire size after calling response_clear!");
+//// errors++;
+//// } else {
+//// if (compare_wires_simple(original_wire,
+//// new_wire, new_size)) {
+//// diag("Wrong wire after calling response_clear!");
+//// errors++;
+//// }
+//// }
+
+//// free(new_wire);
+//// free(original_wire);
+//// free(question_changed_wire);
+//// knot_packet_free(&response);
+
+// return (errors == 0);
+//}
+
+static int test_response_add_opt()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_opt_rr_t opt;
+ opt.payload = 512;
+ opt.ext_rcode = 0;
+ opt.version = EDNS_VERSION_0;
+ opt.flags = 0;
+ opt.options = NULL;
+ opt.option_count = 0;
+ opt.options_max = 0;
+ opt.size = 25; // does it matter?
+
+ lives_ok({
+ if (knot_response_add_opt(NULL, NULL, 0) != KNOT_EBADARG) {
+ diag("Calling response add opt with NULL arguments "
+ "did not result to KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ lived = 0;
+ if (knot_response_add_opt(response,
+ NULL, 0) != KNOT_EBADARG) {
+ diag("Calling response add opt with NULL OPT RR "
+ "did not result to KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_response_add_opt(NULL,
+ &opt, 0) != KNOT_EBADARG) {
+ diag("Calling response add opt with NULL response "
+ "did not result to KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_free(&response);
+ }, "response: add opt NULL tests");
+ errors += lived != 1;
+
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ knot_packet_set_max_size(response, KNOT_PACKET_PREALLOC_RESPONSE * 100);
+ assert(knot_response_init(response) == KNOT_EOK);;
+
+ if (knot_response_add_opt(response, &opt, 0) != KNOT_EOK) {
+ diag("Adding valid OPT RR to response "
+ "did not return KNOT_EOK");
+ errors++;
+ }
+
+ opt.payload = response->max_size + 1;
+ if (knot_response_add_opt(response, &opt, 1) != KNOT_EPAYLOAD) {
+ diag("If OPT RR payload is bigger than response max size "
+ "response_add_opt does not return KNOT_EPAYLOAD!");
+ errors++;
+ }
+
+ opt.payload = 0;
+ if (knot_response_add_opt(response, &opt, 1) != KNOT_EBADARG) {
+ diag("Calling response_add_opt with OPT RR payload set to 0 "
+ "did not return KNOT_EBADARG");
+ }
+
+ knot_packet_free(&response);
+ return (errors == 0);
+}
+
+static int test_response_add_generic(int (*func)(knot_packet_t *,
+ const knot_rrset_t *,
+ int, int, int))
+{
+ int errors = 0;
+ int lived = 0;
+
+ lives_ok({
+ if (func(NULL, NULL, 0, 0, 0) != KNOT_EBADARG) {
+ diag("Calling response add rrset with NULL "
+ "arguments did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ lived = 0;
+ if (func(response, NULL, 0, 0, 0) != KNOT_EBADARG) {
+ diag("Calling response add rrset with NULL rrset "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_dname_t *owner =
+ knot_dname_new_from_str("ns.nic.cz.",
+ strlen("ns.nic.cz."),
+ NULL);
+ assert(owner);
+ knot_rrset_t *rrset =
+ knot_rrset_new(owner, KNOT_RRTYPE_A,
+ KNOT_CLASS_IN, 3600);
+ assert(rrset);
+ lived = 0;
+ if (func(NULL, rrset, 0, 0, 0) != KNOT_EBADARG) {
+ diag("Calling response add rrset with NULL response "
+ "did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_rrset_deep_free(&rrset, 1, 0, 0);
+ knot_packet_free(&response);
+ }, "response: rrset adding NULL tests");
+ errors += lived != 1;
+
+ /*!< \todo Test case when KNOT_ESPACE should be returned. */
+ /*!< \todo Compression and so on - should it be tested here? */
+
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+
+ knot_dname_t *owner =
+ knot_dname_new_from_str("ns12.nic.cz.",
+ strlen("ns12.nic.cz."),
+ NULL);
+ assert(owner);
+ knot_rrset_t *rrset =
+ knot_rrset_new(owner, KNOT_RRTYPE_NS,
+ KNOT_CLASS_IN, 3600);
+ assert(rrset);
+ if (func(response, rrset, 0, 0, 0) != KNOT_EOK) {
+ diag("Adding valid RRSet to response did not result to "
+ "KNOT_EOK");
+ errors++;
+ }
+
+ knot_rrset_deep_free(&rrset, 1, 0, 0);
+ knot_packet_free(&response);
+
+ return (errors == 0);
+}
+
+static void test_response_add_rrset()
+{
+ ok(test_response_add_generic(knot_response_add_rrset_answer),
+ "response: add answer rrset");
+ ok(test_response_add_generic(knot_response_add_rrset_authority),
+ "response: add answer authority");
+ ok(test_response_add_generic(knot_response_add_rrset_additional),
+ "response: add answer additional");
+}
+
+static int test_response_add_nsid()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+
+ uint8_t *nsid = (uint8_t *)"knotDNS";
+ uint16_t nsid_size = strlen((char *)nsid);
+ lives_ok({
+ if (knot_response_add_nsid(NULL,
+ NULL, 1) != KNOT_EBADARG) {
+ diag("Calling response add nsid with NULL arguments "
+ "did not return KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+
+ lived = 0;
+ if (knot_response_add_nsid(NULL, nsid,
+ nsid_size) != KNOT_EBADARG) {
+ diag("Calling response add nsid with NULL response "
+ "did not return KNOT_EBADARG");
+ errors++;
+ }
+ lived = 1;
+// lived = 0;
+// if (knot_response_add_nsid(response, nsid,
+// 0) != KNOT_EBADARG) {
+// diag("Calling response add nsid with zero size "
+// "did not return KNOT_EBADARG");
+// errors++;
+// }
+// lived = 1;
+ }, "response: add nsid NULL tests");
+ errors += lived != 1;
+
+ if (knot_response_add_nsid(response, nsid,
+ nsid_size) != KNOT_EOK) {
+ diag("Adding valid nsid to response did not return KNOT_EOK");
+ errors++;
+ }
+
+ knot_packet_free(&response);
+ return (errors == 0);
+}
+
+static const int KNOT_response_TEST_COUNT = 14;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_response_tests_count(int argc, char *argv[])
+{
+ return KNOT_response_TEST_COUNT;
+}
+
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_response_tests_run(int argc, char *argv[])
+{
+ ok(test_response_init(), "response: init");
+ ok(test_response_init_query(), "response: init from query");
+// ok(test_response_clear(), "response: clear");
+ ok(test_response_add_opt(), "response: add opt");
+ test_response_add_rrset();
+ ok(test_response_add_nsid(), "response: add nsid");
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/response_tests.h b/src/tests/libknot/libknot/response_tests.h
new file mode 100644
index 0000000..c9a117b
--- /dev/null
+++ b/src/tests/libknot/libknot/response_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_response_TESTS_H_
+#define _KNOTD_response_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api response_tests_api;
+
+#endif /* _KNOTD_response_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/rrset_tests.c b/src/tests/libknot/libknot/rrset_tests.c
new file mode 100644
index 0000000..fa75195
--- /dev/null
+++ b/src/tests/libknot/libknot/rrset_tests.c
@@ -0,0 +1,888 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "tests/libknot/libknot/rrset_tests.h"
+#include "libknot/common.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/rrset.h"
+#include "libknot/dname.h"
+#include "libknot/rdata.h"
+#include "libknot/util/utils.h"
+#include "libknot/zone/node.h"
+#include "libknot/util/debug.h"
+
+static int knot_rrset_tests_count(int argc, char *argv[]);
+static int knot_rrset_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api rrset_tests_api = {
+ "DNS library - rrset", //! Unit name
+ &knot_rrset_tests_count, //! Count scheduled tests
+ &knot_rrset_tests_run //! Run scheduled tests
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Unit implementation.
+ */
+
+static knot_node_t *NODE_ADDRESS = (knot_node_t *)0xDEADBEEF;
+
+enum { TEST_RRSETS = 6 , TEST_RRSIGS = 6};
+
+//void *RRSIG_ADDRESS = (void *)0xDEADBEEF;
+//void *RRSIG_FIRST = RRSIG_ADDRESS + 10;
+
+struct test_domain {
+ char *str;
+ char *wire;
+ uint size;
+ char *labels;
+ short label_count;
+};
+
+struct test_rrset {
+ char *owner;
+ uint16_t type;
+ uint16_t rclass;
+ uint32_t ttl;
+ knot_rdata_t *rdata;
+ const knot_rrset_t *rrsigs;
+};
+
+/* this has to changed */
+static const char *signature_strings[TEST_RRSIGS] =
+{"signature 1", "signature 2", "signature 3",
+ "signature 4", "signature 5", "signature 6"};
+
+enum {
+ RR_DNAMES_COUNT = 3,
+ RR_ITEMS_COUNT = 3,
+ RR_RDATA_COUNT = 4,
+};
+
+enum { TEST_DOMAINS_OK = 8 };
+
+static knot_dname_t RR_DNAMES[RR_DNAMES_COUNT] =
+ { {{}, (uint8_t *)"\7example\3com", 13, NULL}, //0's at the end are added
+ {{}, (uint8_t *)"\3ns1\7example\3com", 17, NULL},
+ {{}, (uint8_t *)"\3ns2\7example\3com", 17, NULL} };
+
+/* 192.168.1.1 */
+static uint8_t address[4] = {0xc0, 0xa8, 0x01, 0x01};
+
+static knot_rdata_item_t RR_ITEMS[RR_ITEMS_COUNT] =
+ { {.dname = &RR_DNAMES[1]},
+ {.dname = &RR_DNAMES[2]},
+ {.raw_data = (uint16_t *)address} };
+
+/*! \warning Do not change the order. */
+/* TODO this does not work as expected */
+static knot_rdata_t RR_RDATA[RR_RDATA_COUNT] =
+ { {&RR_ITEMS[0], 1, &RR_RDATA[0]}, /* first ns */
+ {&RR_ITEMS[1], 1, &RR_RDATA[1]}, /* second ns */
+ {&RR_ITEMS[0], 1, &RR_RDATA[3]}, /* both in cyclic list */
+ {&RR_ITEMS[1], 1, &RR_RDATA[2]} };
+
+/*! \warning Do not change the order in those, if you want to test some other
+ * feature with new dname, add it at the end of these arrays.
+ */
+static const struct test_domain
+ test_domains_ok[TEST_DOMAINS_OK] = {
+ { "abc.test.domain.com.", "\3abc\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "xyz.test.domain.com.", "\3xyz\4test\6domain\3com", 21,
+ "\x0\x4\x9\x10", 4 },
+ { "some.test.domain.com.", "\4some\4test\6domain\3com", 22,
+ "\x0\x5\xA\x11", 4 },
+ { "test.domain.com.", "\4test\6domain\3com", 17,
+ "\x0\x5\xC", 3 },
+ { ".", "\0", 1,
+ "", 0 },
+ { "foo.bar.net.", "\3foo\3bar\3net", 13,
+ "\x0\x4\x8", 3},
+ { "bar.net.", "\3bar\3net", 9,
+ "\x0\x4", 2}
+};
+
+static struct test_rrset test_rrsets[TEST_RRSETS] = {
+ { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example2.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example3.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL },
+ { "example.com.", KNOT_RRTYPE_NS, KNOT_CLASS_IN,
+ 3600, NULL, NULL }
+};
+
+static const struct test_rrset test_rrsigs[TEST_RRSIGS] = {
+ { "example.com.", 46, 1, 3600, NULL },
+ { "example2.com.", 46, 1, 3600, NULL },
+ { "example3.com.", 46, 1, 3600, NULL },
+ { "example4.com.", 46, 1, 3600, NULL },
+ { "example5.com.", 46, 1, 3600, NULL },
+ { "example6.com.", 46, 1, 3600, NULL }
+};
+
+static void generate_rdata(uint8_t *data, int size)
+{
+ for (int i = 0; i < size; ++i) {
+ data[i] = rand() % 256;
+ }
+}
+
+static int fill_rdata_r(uint8_t *data, int max_size, uint16_t rrtype,
+ knot_rdata_t *rdata)
+{
+ assert(rdata != NULL);
+ assert(data != NULL);
+ assert(max_size > 0);
+
+ uint8_t *pos = data;
+ int used = 0;
+ int wire_size = 0;
+
+// note("Filling RRType %u", rrtype);
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrtype);
+
+ uint item_count = desc->length;
+ knot_rdata_item_t *items =
+ (knot_rdata_item_t *)malloc(item_count
+ * sizeof(knot_rdata_item_t));
+
+ for (int i = 0; i < item_count; ++i) {
+ uint size = 0;
+ int domain = 0;
+ knot_dname_t *dname = NULL;
+ int binary = 0;
+ int stored_size = 0;
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ dname = knot_dname_new_from_wire(
+ (uint8_t *)test_domains_ok[0].wire,
+ test_domains_ok[0].size, NULL);
+ assert(dname != NULL);
+// note("Created domain name: %s",
+// knot_dname_name(dname));
+// note("Domain name ptr: %p", dname);
+ domain = 1;
+ size = knot_dname_size(dname);
+// note("Size of created domain name: %u", size);
+ assert(size < KNOT_MAX_RDATA_ITEM_SIZE);
+ // store size of the domain name
+ *(pos++) = size;
+ // copy the domain name
+ memcpy(pos, knot_dname_name(dname), size);
+ pos += size;
+ break;
+ default:
+ binary = 1;
+ size = rand() % KNOT_MAX_RDATA_ITEM_SIZE;
+ }
+
+ if (binary) {
+ // Rewrite the actual 2 bytes in the data array
+ // with length.
+ // (this is a bit ugly, but does the work ;-)
+ knot_wire_write_u16(pos, size);
+ //*pos = size;
+ }
+
+ //note("Filling %u bytes", size);
+ used += size;
+ assert(used < max_size);
+
+ if (domain) {
+ items[i].dname = dname;
+ wire_size += knot_dname_size(dname);
+/* note("Saved domain name ptr on index %d: %p",
+ i, items[i].dname); */
+ } else {
+ free(dname);
+// note("Saved raw data ptr on index %d: %p",i, pos);
+ items[i].raw_data = (uint16_t *)pos;
+ pos += size;
+ wire_size += size;
+ if (binary && !stored_size) {
+ wire_size -= 2;
+ }
+ }
+ }
+
+ int res = knot_rdata_set_items(rdata, items, item_count);
+ if (res != 0) {
+ diag("knot_rdata_set_items() returned %d.", res);
+ free(items);
+ return -1;
+ } else {
+ free(items);
+ return wire_size;
+ }
+}
+
+/* fills test_rrsets with random rdata when empty */
+static void create_rdata()
+{
+ knot_rdata_t *r;
+
+ uint8_t *data =
+ malloc(sizeof(uint8_t) * KNOT_MAX_RDATA_WIRE_SIZE);
+
+ assert(data);
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ if (test_rrsets[i].rdata == NULL) {
+ r = knot_rdata_new();
+
+ /* from rdata tests */
+ generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+ if (fill_rdata_r(data, KNOT_MAX_RDATA_WIRE_SIZE,
+ test_rrsets[i].type, r) <= 0) {
+ diag("Error creating rdata!");
+
+ }
+
+ test_rrsets[i].rdata = r;
+ }
+ }
+
+ free(data);
+}
+
+static int check_rrset(const knot_rrset_t *rrset, int i,
+ int check_rdata, int check_items,
+ int check_rrsigs)
+{
+ /* following implementation should be self-explanatory */
+ int errors = 0;
+
+ if (rrset == NULL) {
+ diag("RRSet not created!");
+ return 1;
+ }
+
+ char *owner = knot_dname_to_str(rrset->owner);
+ if (strcmp(owner, test_rrsets[i].owner) != 0) {
+ diag("OWNER domain name wrong: '%s' (should be '%s')",
+ owner, test_rrsets[i].owner);
+ ++errors;
+ }
+ free(owner);
+
+ if (rrset->type != test_rrsets[i].type) {
+ diag("TYPE wrong: %u (should be: %u)", rrset->type,
+ test_rrsets[i].type);
+ ++errors;
+ }
+
+ if (rrset->rclass != test_rrsets[i].rclass) {
+ diag("CLASS wrong: %u (should be: %u)", rrset->rclass,
+ test_rrsets[i].rclass);
+ ++errors;
+ }
+
+ if (rrset->ttl != test_rrsets[i].ttl) {
+ diag("TTL wrong: %u (should be: %u)", rrset->ttl,
+ test_rrsets[i].ttl);
+ ++errors;
+ }
+
+ if (check_rdata) {
+ /* TODO use rdata_compare */
+ knot_rdata_t *rdata = rrset->rdata;
+
+ if (rdata == NULL) {
+ diag("There are no RDATAs in the RRSet");
+ ++errors;
+ }
+
+ if (rdata != NULL) {
+ while (rdata->next != NULL &&
+ rdata->next != rrset->rdata) {
+ rdata = rdata->next;
+ }
+ if (rdata->next == NULL) {
+ diag("The list of RDATAs is not cyclic!");
+ ++errors;
+ } else {
+ assert(rdata->next == rrset->rdata);
+ }
+ }
+ }
+
+ if (check_items) {
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+ if (knot_rdata_compare(rrset->rdata,
+ test_rrsets[i].rdata,
+ desc->wireformat) != 0) {
+ diag("Rdata items do not match.");
+ errors++;
+ }
+ }
+
+ /* TODO this deserves a major improvement!!! */
+
+ /*
+ * Will work only with null terminated strings,
+ * consider changing to more versatile implementation
+ */
+
+ /* How about, once it's tested, using rdata_compare */
+
+ if (check_rrsigs) {
+
+ const knot_rrset_t *rrsigs;
+
+ rrsigs = knot_rrset_rrsigs(rrset);
+ if (strcmp((const char *)rrsigs->rdata->items[0].raw_data,
+ signature_strings[i])) {
+ diag("Signatures are not equal"
+ "to those set when creating."
+ "Comparing %s with %s",
+ rrsigs->rdata->items[0].raw_data,
+ signature_strings[i]);
+ errors++;
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_create()
+{
+ int errors = 0;
+
+ for (int i = 0; i < TEST_RRSETS; ++i) {
+ knot_dname_t *owner = knot_dname_new_from_str(
+ test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner),
+ NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+ knot_rrset_t *rrset = knot_rrset_new(owner,
+ test_rrsets[i].type,
+ test_rrsets[i].rclass,
+ test_rrsets[i].ttl);
+
+ errors += check_rrset(rrset, i, 0, 0, 0);
+
+ knot_rrset_free(&rrset);
+ knot_dname_free(&owner);
+ }
+
+ //diag("Total errors: %d", errors);
+
+ return (errors == 0);
+}
+
+/* Not implemented - no way how to test unfreed memory from here (yet) */
+static int test_rrset_delete()
+{
+ return 0;
+}
+
+static int test_rrset_add_rdata()
+{
+ /* rdata add */
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ knot_dname_t *owner = knot_dname_new_from_str(
+ test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner),
+ NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+
+ knot_rrset_t *rrset = knot_rrset_new(owner,
+ test_rrsets[i].type,
+ test_rrsets[i].rclass,
+ test_rrsets[i].ttl);
+
+ knot_rrset_add_rdata(rrset, test_rrsets[i].rdata);
+
+ errors += check_rrset(rrset, i, 1, 0, 0);
+
+ knot_rrset_free(&rrset);
+ knot_dname_free(&owner);
+ }
+
+ /* test whether adding works properly = keeps order of added elements */
+
+ /*
+ * Beware, this is dependent on the internal structure of rrset and
+ * may change.
+ */
+
+ knot_rrset_t *rrset = knot_rrset_new(NULL, 0, 0, 0);
+
+ knot_rdata_t *r;
+
+ knot_rdata_item_t *item;
+
+ static const char *test_strings[10] =
+ { "-2", "9", "2", "10", "1", "5", "8", "4", "6", "7" };
+
+ /* add items */
+
+ for (int i = 0; i < 10; i++) {
+ r = knot_rdata_new();
+ item = malloc(sizeof(knot_rdata_item_t));
+ item->raw_data = (uint16_t *)test_strings[i];
+ //following statement creates a copy
+ knot_rdata_set_items(r, item, 1);
+ knot_rrset_add_rdata(rrset, r);
+ free(item);
+ }
+
+ knot_rdata_t *tmp = rrset->rdata;
+
+ /* check if order has been kept */
+
+ int i = 0;
+ while (tmp->next != rrset->rdata && !errors) {
+ if (strcmp(test_strings[i], (char *)tmp->items[0].raw_data)) {
+ diag("Adding RDATA error!, is %s should be %s",
+ tmp->items[0].raw_data, test_strings[i]);
+ errors++;
+ }
+ i++;
+ tmp = tmp->next;
+
+ }
+
+ tmp = rrset->rdata;
+
+ knot_rdata_t *next;
+
+ while (tmp->next != rrset->rdata) {
+ next = tmp->next;
+ knot_rdata_free(&tmp);
+ tmp = next;
+ }
+
+ knot_rdata_free(&tmp);
+
+ knot_rrset_free(&rrset);
+
+ return (errors == 0);
+}
+
+static int test_rrset_rrsigs()
+{
+ int errors = 0;
+
+ knot_rdata_item_t *item;
+
+ knot_rdata_t *tmp;
+
+ knot_dname_t *owner;
+
+ knot_rrset_t *rrset;
+
+ /* Gets rrsigs and checks, if signatures are the same */
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ owner = knot_dname_new_from_str(test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner), NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+
+ rrset = knot_rrset_new(owner, test_rrsets[i].type,
+ test_rrsets[i].rclass, test_rrsets[i].ttl);
+
+ knot_rrset_add_rdata(rrset, test_rrsets[i].rdata);
+
+ //owners are the same
+
+ assert(TEST_RRSETS == TEST_RRSIGS);
+
+ knot_rrset_t *rrsig = knot_rrset_new(owner,
+ test_rrsigs[i].type,
+ test_rrsigs[i].rclass,
+ test_rrsigs[i].ttl);
+
+ tmp = knot_rdata_new();
+ item = malloc(sizeof(knot_rdata_item_t));
+ /* signature is just a string,
+ * should be sufficient for testing */
+ item->raw_data = (uint16_t *)signature_strings[i];
+ knot_rdata_set_items(tmp, item, 1);
+ knot_rrset_add_rdata(rrsig, tmp);
+
+ if (knot_rrset_set_rrsigs(rrset, rrsig)
+ != 0) {
+ diag("Could not set rrsig");
+ errors++;
+ }
+ errors += check_rrset(rrset, i, 0, 0, 1);
+ knot_rrset_free(&rrset);
+ free(item);
+ knot_rdata_free(&tmp);
+ knot_rrset_free(&rrsig);
+ }
+ return (errors == 0);
+}
+
+static int test_rrset_merge()
+{
+ knot_rrset_t *merger1;
+ knot_rrset_t *merger2;
+ knot_dname_t *owner1;
+ knot_dname_t *owner2;
+
+ int r;
+
+ owner1 = knot_dname_new_from_str(test_rrsets[3].owner,
+ strlen(test_rrsets[3].owner), NULL);
+ merger1 = knot_rrset_new(owner1, test_rrsets[3].type,
+ test_rrsets[3].rclass,
+ test_rrsets[3].ttl);
+
+ knot_rrset_add_rdata(merger1, test_rrsets[3].rdata);
+
+ owner2 = knot_dname_new_from_str(test_rrsets[4].owner,
+ strlen(test_rrsets[4].owner), NULL);
+ merger2 = knot_rrset_new(owner2, test_rrsets[4].type,
+ test_rrsets[4].rclass,
+ test_rrsets[4].ttl);
+
+ knot_rrset_add_rdata(merger2, test_rrsets[4].rdata);
+
+// knot_rrset_dump(merger1, 1);
+
+ int ret = 0;
+ if ((ret = knot_rrset_merge((void **)&merger1,
+ (void **)&merger2)) != 0) {
+ diag("Could not merge rrsets. (reason %d)", ret);
+ return 0;
+ }
+
+// knot_rrset_dump(merger1, 1);
+
+ r = check_rrset(merger1, 5, 1, 1, 0);
+
+ knot_rrset_free(&merger1);
+ knot_rrset_free(&merger2);
+
+ if (r) {
+ diag("Merged rdata are wrongly set.");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_rrset_owner(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ char *dname_str =
+ knot_dname_to_str(knot_rrset_owner(rrsets[i]));
+ if (strcmp(dname_str, test_rrsets[i].owner)) {
+ diag("Got wrong value for owner from rrset.");
+ errors++;
+ }
+ free(dname_str);
+ }
+ return errors;
+}
+
+static int test_rrset_type(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ if (knot_rrset_type(rrsets[i]) != test_rrsets[i].type) {
+ errors++;
+ diag("Got wrong value for type from rrset.");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_class(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ if (knot_rrset_class(rrsets[i]) != test_rrsets[i].rclass) {
+ errors++;
+ diag("Got wrong value for class from rrset.");
+ }
+ }
+
+ return errors;
+}
+
+static int test_rrset_ttl(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ if (knot_rrset_ttl(rrsets[i]) != test_rrsets[i].ttl) {
+ errors++;
+ diag("Got wrong value for ttl from rrset.");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_ret_rdata(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+
+ knot_rrtype_descriptor_t *desc;
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+
+ desc = knot_rrtype_descriptor_by_type(rrsets[i]->type);
+ assert(desc);
+
+// knot_rdata_dump(test_rrsets[i].rdata, 1);
+ // knot_rdata_dump(rrsets[i]->rdata, 1);
+
+ if (knot_rdata_compare(knot_rrset_rdata(rrsets[i]),
+ test_rrsets[i].rdata,
+ desc->wireformat)) {
+ errors++;
+ diag("Got wrong value for rdata from rrset.");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_get_rdata(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+
+ knot_rrtype_descriptor_t *desc;
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ desc = knot_rrtype_descriptor_by_type(rrsets[i]->type);
+ assert(desc);
+ if (knot_rdata_compare(knot_rrset_get_rdata(rrsets[i]),
+ test_rrsets[i].rdata,
+ desc->wireformat)) {
+ errors++;
+ diag("Got wrong value for rdata from rrset. (Get)");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_ret_rrsigs(knot_rrset_t **rrsets)
+{
+ int errors = 0;
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ /* TODO should I test the insides of structure as well? */
+ if (knot_rrset_rrsigs(rrsets[i]) != test_rrsets[i].rrsigs) {
+ errors++;
+ diag("Got wrong value for rrsigs from rrset.");
+ }
+ }
+ return errors;
+}
+
+static int test_rrset_getters(uint type)
+{
+ int errors = 0;
+
+ knot_rrset_t *rrsets[TEST_RRSETS];
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ knot_dname_t *owner = knot_dname_new_from_str(
+ test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner),
+ NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+ rrsets[i] = knot_rrset_new(owner,
+ test_rrsets[i].type,
+ test_rrsets[i].rclass,
+ test_rrsets[i].ttl);
+
+ knot_rrset_add_rdata(rrsets[i], test_rrsets[i].rdata);
+ }
+
+ switch (type) {
+ case 0: {
+ errors += test_rrset_owner(rrsets);
+ break;
+ }
+ case 1: {
+ errors += test_rrset_type(rrsets);
+ break;
+ }
+ case 2: {
+ errors += test_rrset_class(rrsets);
+ break;
+ }
+ case 3: {
+ errors += test_rrset_ttl(rrsets);
+ break;
+ }
+ case 4: {
+ errors += test_rrset_ret_rdata(rrsets);
+ break;
+ }
+ case 5: {
+ errors += test_rrset_get_rdata(rrsets);
+ break;
+ }
+ case 6: {
+ errors += test_rrset_ret_rrsigs(rrsets);
+ break;
+ }
+ } /* switch */
+
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ knot_dname_free(&rrsets[i]->owner);
+ knot_rrset_free(&rrsets[i]);
+ }
+
+
+ return (errors == 0);
+}
+
+static int test_rrset_deep_free()
+{
+ /*!< \warning Cannot be run when some rdata are on stack! */
+ int errors = 0;
+
+ knot_rrset_t *tmp_rrset;
+ knot_dname_t *owner;
+ for (int i = 0; i < TEST_RRSETS; i++) {
+ owner = knot_dname_new_from_str(
+ test_rrsets[i].owner,
+ strlen(test_rrsets[i].owner),
+ NODE_ADDRESS);
+ if (owner == NULL) {
+ diag("Error creating owner domain name!");
+ return 0;
+ }
+
+ tmp_rrset = knot_rrset_new(owner,
+ test_rrsets[i].type,
+ test_rrsets[i].rclass,
+ test_rrsets[i].ttl);
+
+ knot_rrset_add_rdata(tmp_rrset, test_rrsets[i].rdata);
+
+ knot_rrset_deep_free(&tmp_rrset, 1, 1, 0);
+
+ errors += (tmp_rrset != NULL);
+ }
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static const int KNOT_RRSET_TEST_COUNT = 13;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_rrset_tests_count(int argc, char *argv[])
+{
+ return KNOT_RRSET_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_rrset_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 1;
+
+/* for (int i = 0; i < 4; i++) {
+ knot_rdata_dump(&RR_RDATA[i], 2, 1);
+ printf("%p %p\n", &RR_RDATA[i], (&RR_RDATA)[i]->next);
+ } */
+
+ create_rdata();
+
+ res = test_rrset_create();
+ ok(res, "rrset: create");
+ res_final *= res;
+
+ skip(!res, 11);
+
+ todo();
+
+ ok(res = test_rrset_delete(), "rrset: delete");
+ //res_final *= res;
+
+ endtodo;
+
+ ok(res = test_rrset_getters(0), "rrset: owner");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(1), "rrset: type");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(2), "rrset: class");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(3), "rrset: ttl");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(4), "rrset: rdata");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(5), "rrset: get rdata");
+ res_final *= res;
+
+ ok(res = test_rrset_getters(6), "rrset: rrsigs");
+ res_final *= res;
+
+ ok(res = test_rrset_add_rdata(), "rrset: add_rdata");
+ res_final *= res;
+
+ ok(res = test_rrset_rrsigs(), "rrset: rrsigs manipulation");
+ res_final *= res;
+
+ ok(res = test_rrset_merge(), "rrset: rdata merging");
+ res_final *= res;
+
+ ok(res = test_rrset_deep_free(), "rrset: deep free");
+ res_final *= res;
+
+ endskip; /* !res_create */
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/rrset_tests.h b/src/tests/libknot/libknot/rrset_tests.h
new file mode 100644
index 0000000..b0787d6
--- /dev/null
+++ b/src/tests/libknot/libknot/rrset_tests.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file rrset_tests.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * Contains unit tests for RRSet (knot_rrset_t) and its API.
+ *
+ * Contains tests for:
+ * -
+ */
+#ifndef _KNOTD_RRSET_TESTS_H_
+#define _KNOTD_RRSET_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api rrset_tests_api;
+
+#endif /* _KNOTD_RRSET_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/zone_tests.c b/src/tests/libknot/libknot/zone_tests.c
new file mode 100644
index 0000000..2fdd61a
--- /dev/null
+++ b/src/tests/libknot/libknot/zone_tests.c
@@ -0,0 +1,853 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "tests/libknot/libknot/zone_tests.h"
+#include "libknot/common.h"
+#include "libknot/zone/dname-table.h"
+#include "libknot/zone/zone.h"
+#include "libknot/util/error.h"
+#include "libknot/zone/node.h"
+
+static int knot_zone_tests_count(int argc, char *argv[]);
+static int knot_zone_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zone_tests_api = {
+ "DNS library - zone", //! Unit name
+ &knot_zone_tests_count, //! Count scheduled tests
+ &knot_zone_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+enum { TEST_NODES_GOOD = 7, TEST_NODES_BAD = 1, TRAVERSAL_TYPES = 3};
+
+struct zone_test_node {
+ knot_dname_t owner;
+ knot_node_t *parent;
+};
+
+static struct zone_test_node test_apex =
+{{{}, (uint8_t *)"\3com\0", 5, (uint8_t *)"\x0", 1}, (knot_node_t *)NULL};
+
+static struct zone_test_node test_nodes_bad[TEST_NODES_BAD] = {
+ {{{},(uint8_t *)"\5other\6domain\0", 14, (uint8_t *)"\x0\x6", 2},
+ (knot_node_t *)NULL}
+};
+
+static struct zone_test_node test_nodes_good[TEST_NODES_GOOD] = {
+ {{{}, (uint8_t *)"\7example\3com\0", 13, (uint8_t *)"\x0\x8", 2},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\3www\7example\3com\0", 17, (uint8_t *)"\x0\x4\xC", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\7another\6domain\3com\0", 20, (uint8_t *)"\x0\x8\xF", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\5mail1\7example\3com\0", 19, (uint8_t *)"\x0\x6\xE", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\5mail2\7example\3com\0", 19, (uint8_t *)"\x0\x6\xE", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\3smb\7example\3com\0", 17, (uint8_t *)"\x0\x4\xC", 3},
+ (knot_node_t *)NULL},
+ {{{}, (uint8_t *)"\4smtp\7example\3com\0", 18, (uint8_t *)"\x0\x5\xD", 3},
+ (knot_node_t *)NULL},
+};
+
+static int test_zone_check_node(const knot_node_t *node,
+ const struct zone_test_node *test_node,
+ int test_parent)
+{
+ return (node->owner == &test_node->owner) &&
+ ((test_parent) ? node->parent == test_node->parent : 1);
+}
+
+static int test_zone_create(knot_zone_contents_t **zone)
+{
+// knot_dname_t *dname = knot_dname_new_from_wire(
+// test_apex.owner.name, test_apex.owner.size, NULL);
+// assert(dname);
+
+ knot_node_t *node = knot_node_new(&test_apex.owner,
+ test_apex.parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create zone apex.");
+ return 0;
+ }
+
+ *zone = knot_zone_contents_new(node, 0, 0, NULL);
+
+ if ((*zone) == NULL) {
+ diag("zone: Failed to create zone.");
+ knot_node_free(&node, 1, 0);
+ return 0;
+ }
+
+ if ((*zone)->apex != node) {
+ diag("zone: Zone apex not set right.");
+ knot_node_free(&node, 1, 0);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_zone_add_node(knot_zone_contents_t *zone, int nsec3)
+{
+ /*
+ * NSEC3 nodes are de facto identical to normal nodes, so there is no
+ * need for separate tests. The only difference is where are they stored
+ * in the zone structure.
+ */
+
+ int errors = 0;
+ int res = 0;
+
+ //note("Good nodes");
+
+ for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+ knot_node_t *node = knot_node_new(&test_nodes_good[i].owner,
+ test_nodes_good[i].parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, node, 0, 0, 0)
+ : knot_zone_contents_add_node(zone, node, 0, 0, 0))) != 0) {
+ diag("zone: Failed to insert node into zone (returned"
+ " %d).", res);
+ knot_node_free(&node, 0, 0);
+ ++errors;
+ }
+ /* TODO check values in the node as well */
+ }
+
+ //note("Bad nodes");
+
+ for (int i = 0; i < TEST_NODES_BAD; ++i) {
+ knot_node_t *node = knot_node_new(&test_nodes_bad[i].owner,
+ test_nodes_bad[i].parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, node, 0, 0, 0)
+ : knot_zone_contents_add_node(zone, node, 0, 0, 0))) !=
+ KNOT_EBADZONE) {
+ diag("zone: Inserting wrong node did not result in"
+ "proper return value (%d instead of %d).", res,
+ KNOT_EBADZONE);
+ ++errors;
+ }
+ knot_node_free(&node, 0, 0);
+ }
+
+ //note("NULL zone");
+
+ note("Inserting into NULL zone...\n");
+
+ knot_node_t *node = knot_node_new(&test_nodes_good[0].owner,
+ test_nodes_good[0].parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(NULL, node, 0, 0, 0)
+ : knot_zone_contents_add_node(NULL, node, 0, 0, 0))) != KNOT_EBADARG) {
+ diag("zone: Inserting node to NULL zone did not result in"
+ "proper return value (%d instead of %d)", res,
+ KNOT_EBADARG);
+ ++errors;
+ }
+
+ knot_node_free(&node, 0, 0);
+
+ //note("NULL node");
+ note("Inserting NULL node...\n");
+
+ if ((res = ((nsec3) ? knot_zone_contents_add_nsec3_node(zone, NULL, 0, 0, 0)
+ : knot_zone_contents_add_node(zone, NULL, 0, 0, 0))) != KNOT_EBADARG) {
+ diag("zone: Inserting NULL node to zone did not result in"
+ "proper return value (%d instead of %d)", res,
+ KNOT_EBADARG);
+ ++errors;
+ }
+
+ if (!nsec3) {
+ //note("Inserting Apex again...\n");
+
+ node = knot_node_new(&test_apex.owner, test_apex.parent, 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ //note("Apex again");
+
+ if ((res = knot_zone_contents_add_node(zone, node, 0, 0, 0)) !=
+ KNOT_EBADZONE) {
+ diag("zone: Inserting zone apex again did not result in"
+ "proper return value (%d instead of -2)",
+ KNOT_EBADZONE);
+ ++errors;
+ }
+
+ knot_node_free(&node, 0, 0);
+ }
+
+ // check if all nodes are inserted
+ //int nodes = 0;
+ if (!nsec3
+ && !test_zone_check_node(knot_zone_contents_apex(zone), &test_apex, !nsec3)) {
+ diag("zone: Apex of zone not right.");
+// diag("Apex owner: %s (%p), apex parent: %p\n",
+// knot_dname_to_str(knot_zone_apex(zone)->owner),
+// knot_zone_apex(zone)->owner,
+// knot_zone_apex(zone)->parent);
+// diag("Should be: owner: %s (%p), parent: %p\n",
+// knot_dname_to_str(&test_apex.owner),
+// &test_apex.owner,
+// test_apex.parent);
+ ++errors;
+ }
+ //++nodes;
+ for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+ const knot_node_t *n = ((nsec3) ? knot_zone_contents_find_nsec3_node(
+ zone, &test_nodes_good[i].owner) :
+ knot_zone_contents_find_node(zone, &test_nodes_good[i].owner));
+ if (n == NULL) {
+ diag("zone: Missing node with owner %s",
+ test_nodes_good[i].owner.name);
+ ++errors;
+ continue;
+ }
+
+ if (!test_zone_check_node(n, &test_nodes_good[i], !nsec3)) {
+ diag("zone: Node does not match: owner: %s (should be "
+ "%s), parent: %p (should be %p)",
+ n->owner->name, test_nodes_good[i].owner.name,
+ n->parent, test_nodes_good[i].parent);
+ ++errors;
+ }
+ //++nodes;
+ }
+
+ //note("zone: %d nodes in the zone (including apex)", nodes);
+
+ return (errors == 0);
+}
+
+static int test_zone_get_node(knot_zone_contents_t *zone, int nsec3)
+{
+ int errors = 0;
+
+ for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+ if (((nsec3) ? knot_zone_contents_get_nsec3_node(
+ zone, &test_nodes_good[i].owner)
+ : knot_zone_contents_get_node(zone, &test_nodes_good[i].owner))
+ == NULL) {
+ diag("zone: Node (%s) not found in zone.",
+ (char *)test_nodes_good[i].owner.name);
+ ++errors;
+ }
+ }
+
+ for (int i = 0; i < TEST_NODES_BAD; ++i) {
+ if (((nsec3) ? knot_zone_contents_get_nsec3_node(
+ zone, &test_nodes_bad[i].owner)
+ : knot_zone_contents_get_node(zone, &test_nodes_bad[i].owner))
+ != NULL) {
+ diag("zone: Node (%s) found in zone even if it should"
+ "not be there.",
+ (char *)test_nodes_bad[i].owner.name);
+ ++errors;
+ }
+ }
+
+ if (((nsec3)
+ ? knot_zone_contents_get_nsec3_node(NULL, &test_nodes_good[0].owner)
+ : knot_zone_contents_get_node(NULL, &test_nodes_good[0].owner)) != NULL) {
+ diag("zone: Getting node from NULL zone did not result in"
+ "proper return value (NULL)");
+ ++errors;
+ }
+
+ if (((nsec3) ? knot_zone_contents_get_nsec3_node(zone, NULL)
+ : knot_zone_contents_get_node(zone, NULL)) != NULL) {
+ diag("zone: Getting node with NULL owner from zone did not "
+ "result in proper return value (NULL)");
+ ++errors;
+ }
+
+ if (!nsec3 && knot_zone_contents_get_node(zone, &test_apex.owner) == NULL) {
+ diag("zone: Getting zone apex from the zone failed");
+ ++errors;
+ }
+
+ return (errors == 0);
+}
+
+static int test_zone_find_node(knot_zone_contents_t *zone, int nsec3)
+{
+ int errors = 0;
+
+ for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+ if (((nsec3) ? knot_zone_contents_find_nsec3_node(
+ zone, &test_nodes_good[i].owner)
+ : knot_zone_contents_find_node(zone, &test_nodes_good[i].owner))
+ == NULL) {
+ diag("zone: Node (%s) not found in zone.",
+ (char *)test_nodes_good[i].owner.name);
+ ++errors;
+ }
+ }
+
+ for (int i = 0; i < TEST_NODES_BAD; ++i) {
+ if (((nsec3) ? knot_zone_contents_find_nsec3_node(
+ zone, &test_nodes_bad[i].owner)
+ : knot_zone_contents_find_node(zone, &test_nodes_bad[i].owner))
+ != NULL) {
+ diag("zone: Node (%s) found in zone even if it should"
+ "not be there.",
+ (char *)test_nodes_bad[i].owner.name);
+ ++errors;
+ }
+ }
+
+ if (((nsec3)
+ ? knot_zone_contents_find_nsec3_node(NULL, &test_nodes_good[0].owner)
+ : knot_zone_contents_find_node(NULL, &test_nodes_good[0].owner)) != NULL) {
+ diag("zone: Finding node from NULL zone did not result in"
+ "proper return value (NULL)");
+ ++errors;
+ }
+
+ if (((nsec3) ? knot_zone_contents_find_nsec3_node(zone, NULL)
+ : knot_zone_contents_find_node(zone, NULL)) != NULL) {
+ diag("zone: Finding node with NULL owner from zone did not "
+ "result in proper return value (NULL)");
+ ++errors;
+ }
+
+ if (!nsec3 && knot_zone_contents_find_node(zone, &test_apex.owner) == NULL) {
+ diag("zone: Finding zone apex from the zone failed");
+ ++errors;
+ }
+
+ return (errors == 0);
+}
+
+//static void test_zone_destroy_node_from_tree(knot_node_t *node,
+// void *data)
+//{
+// UNUSED(data);
+// knot_node_free(&node, 0);
+//}
+
+/* explained below */
+static size_t node_index = 0;
+
+/*! \brief
+ * This function will overwrite parent field in node structure -
+ * we don't (and can't, with current structures) use it in these tests anyway.
+ * Since zone structure itself has no count field, only option known to me
+ * is (sadly) to use a global variable.
+ */
+static void tmp_apply_function(knot_node_t *node, void *data)
+{
+ node->parent = (knot_node_t *)node_index;
+ node_index++;
+}
+
+/* \note Since I am unaware of a way how to get a return value from traversal
+ * functions, I will use (hopefully for the last time here) global variable
+ */
+
+static int compare_ok = 1;
+
+static void tmp_compare_function(knot_node_t *node, void *data)
+{
+ /* node_index will start set to zero */
+ if (node->parent != (knot_node_t *)node_index) {
+ compare_ok = 0;
+ return;
+ } else if (!compare_ok) {
+ diag("Traversal function has partially set values right");
+ }
+ node->parent = NULL;
+ node_index++;
+}
+
+static int test_zone_tree_apply(knot_zone_contents_t *zone,
+ int type, int nsec3)
+{
+
+ assert(node_index == 0);
+ assert(compare_ok == 1);
+
+ int (*traversal_func)(knot_zone_contents_t *zone,
+ void (*function)(knot_node_t *node,
+ void *data),
+ void *data);
+
+ switch (type) {
+ case 0: {
+ if (nsec3) {
+ traversal_func =
+ &knot_zone_contents_nsec3_apply_postorder;
+ diag("Testing postorder traversal");
+ } else {
+ traversal_func =
+ &knot_zone_contents_tree_apply_postorder;
+ diag("Testing postorder traversal - NSEC3");
+ }
+ break;
+ }
+ case 1: {
+ if (nsec3) {
+ traversal_func =
+ &knot_zone_contents_nsec3_apply_inorder;
+ diag("Testing inorder traversal");
+ } else {
+ traversal_func =
+ &knot_zone_contents_tree_apply_inorder;
+ diag("Testing inorder traversal - NSEC3");
+ }
+ break;
+ }
+ case 2: {
+ if (nsec3) {
+ traversal_func =
+ &knot_zone_contents_nsec3_apply_inorder_reverse;
+ diag("Testing inorder reverse traversal");
+ } else {
+ traversal_func =
+ &knot_zone_contents_tree_apply_inorder_reverse;
+ diag("Testing inorder reverse "
+ "traversal - NSEC3");
+ }
+ break;
+ }
+ default: {
+ diag("Unknown traversal function type");
+ return 0;
+ }
+ }
+
+ /*
+ * This will iterate through tree and set node->parent field values
+ * from 0 to number of nodes.
+ */
+
+ traversal_func(zone, &tmp_apply_function, NULL);
+
+ node_index = 0;
+
+ /*
+ * This will check whether the values were set accordingly.
+ */
+
+ traversal_func(zone, &tmp_compare_function, NULL);
+
+ int ret = compare_ok;
+
+ compare_ok = 1;
+ node_index = 0;
+
+ return (ret);
+}
+
+/* Tests all kinds of zone traversals, explainded above */
+static int test_zone_traversals(knot_zone_contents_t *zone)
+{
+ for (int i = 0; i < TRAVERSAL_TYPES; i++) {
+ for (int j = 0; j < 2; j++) {
+ if (!test_zone_tree_apply(zone, i, j)) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+struct zone_test_param {
+ /* Times 2 so that we don't have to mess with mallocs. */
+ knot_node_t *knot_node_array[TEST_NODES_GOOD * 5];
+ knot_dname_t *table_node_array[TEST_NODES_GOOD * 5];
+ size_t count;
+};
+
+static void tree_node_to_array(knot_node_t *node, void *data)
+{
+ struct zone_test_param *param = (struct zone_test_param *)data;
+ param->knot_node_array[param->count++] = node;
+}
+
+static void tree_dname_node_to_array(knot_dname_t *node,
+ void *data)
+{
+ struct zone_test_param *param = (struct zone_test_param *)data;
+ param->table_node_array[param->count++] = node;
+}
+
+extern int compare_wires_simple(uint8_t *w1, uint8_t *w2, uint count);
+static int test_zone_shallow_copy()
+{
+ int errors = 0;
+ int lived = 0;
+ knot_dname_t *apex_dname =
+ knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz"), NULL);
+ assert(apex_dname);
+ knot_node_t *apex_node =
+ knot_node_new(apex_dname, NULL, 0);
+ assert(apex_node);
+ lives_ok({
+ if (knot_zone_contents_shallow_copy(NULL, NULL) != KNOT_EBADARG) {
+ diag("Calling zone_shallow_copy with NULL "
+ "arguments did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ knot_zone_contents_t *zone = knot_zone_contents_new(apex_node,
+ 0, 1, 0);
+ if (knot_zone_contents_shallow_copy(zone, NULL) != KNOT_EBADARG) {
+ diag("Calling zone_shallow_copy with NULL destination "
+ "zone argument did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_contents_shallow_copy(NULL, &zone) != KNOT_EBADARG) {
+ diag("Calling zone_shallow_copy with NULL source "
+ "zone argument did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_contents_shallow_copy(zone, &zone) != KNOT_EBADARG) {
+ diag("Calling zone_shallow_copy with identical source "
+ "and destination zone did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ knot_zone_contents_free(&zone);
+ }, "zone: shallow copy NULL tests");
+ errors += lived != 1;
+
+ knot_dname_t *d = knot_dname_deep_copy(&test_nodes_good[0].owner);
+ if (d == NULL) {
+ return 0;
+ }
+ knot_node_t *n = knot_node_new(d, NULL, 0);
+
+ /* example.com. */
+// knot_zone_t *from_zone =
+// knot_zone_new(knot_node_new(&test_nodes_good[0].owner,
+// test_nodes_good[0].parent, 0), 10, 1);
+ knot_zone_t *from_zone = knot_zone_new(n, 10, 1);
+ knot_zone_contents_t *from = knot_zone_get_contents(from_zone);
+
+ /* Add nodes to zone. */
+ for (int i = 1; i < TEST_NODES_GOOD; ++i) {
+ knot_dname_t *d = knot_dname_deep_copy(&test_nodes_good[i].owner);
+ if (d == NULL) {
+ return 0;
+ }
+ knot_node_t *node = knot_node_new(d, test_nodes_good[i].parent,
+ 0);
+ if (node == NULL) {
+ diag("zone: Could not create node.");
+ return 0;
+ }
+
+ if (knot_zone_contents_add_node(from, node, 1, 1, 1) != KNOT_EOK) {
+ diag("zone: Could not add node. %s",
+ knot_dname_to_str(node->owner));
+// return 0;
+ }
+ }
+
+ /* Make a copy of zone */
+ knot_zone_contents_t *to = NULL;
+ int ret = 0;
+ if ((ret = knot_zone_contents_shallow_copy(from, &to) != KNOT_EOK)) {
+ diag("Could not copy zone! %s", knot_strerror(ret));
+ return 0;
+ }
+
+ assert(to);
+
+ /* Compare non-tree parts of the zone. */
+// if (from->data != to->data) {
+// diag("Zone data field wrong after shallow copy!");
+// errors++;
+// }
+
+// if (from->dtor != to->dtor) {
+// diag("Zone data destructor field wrong after shallow copy!");
+// errors++;
+// }
+
+ if (from->node_count != to->node_count) {
+ diag("Zone node count data field wrong after shallow copy!");
+ errors++;
+ }
+
+// if (from->version != to->version) {
+// diag("Zone version data field wrong after shallow copy!");
+// errors++;
+// }
+
+ if (from->apex != to->apex) {
+ diag("Zone apex differ after shallow copy!");
+ }
+
+ if (compare_wires_simple((uint8_t *)(&from->nsec3_params),
+ (uint8_t *)(&to->nsec3_params),
+ sizeof(from->nsec3_params)) != 0) {
+ diag("Nsec3_params data field wrong after shallow copy!");
+ errors++;
+ }
+
+ if (from->nodes == to->nodes) {
+ diag("Copied zones have identical trees!");
+ errors++;
+ }
+
+ if (from->nsec3_nodes == to->nsec3_nodes) {
+ diag("Copied zones have identical trees!");
+ errors++;
+ }
+
+ /* Compare nodes, convert tree to array then compare those arrays. */
+ struct zone_test_param param1;
+ memset(&param1, 0, sizeof(struct zone_test_param));
+
+ knot_zone_contents_tree_apply_inorder(from, tree_node_to_array,
+ (void *)&param1);
+
+ struct zone_test_param param2;
+ memset(&param2, 0, sizeof(struct zone_test_param));
+
+ knot_zone_contents_tree_apply_inorder(to, tree_node_to_array,
+ (void *)&param2);
+
+ if (param1.count != param2.count) {
+ diag("wrong tree");
+ return 0;
+ }
+
+ for (int i = 0; i < param1.count; i++) {
+ if (param1.knot_node_array[i] !=
+ param2.knot_node_array[i]) {
+ diag("wrong tree");
+ return 0;
+ }
+ }
+
+ param1.count = 0;
+ knot_dname_table_tree_inorder_apply(from->dname_table,
+ tree_dname_node_to_array,
+ (void *)&param1);
+
+ param2.count = 0;
+ knot_dname_table_tree_inorder_apply(to->dname_table,
+ tree_dname_node_to_array,
+ (void *)&param2);
+
+ if (param1.count != param2.count) {
+ diag("wrong table count");
+ return 0;
+ }
+
+ for (int i = 0; i < param1.count; i++) {
+ if (param1.table_node_array[i] != param2.table_node_array[i]) {
+ diag("wrong table nodes");
+ errors++;
+ }
+ }
+
+#ifdef USE_HASH_TABLE
+ if (from->table) {
+ if (from->table == to->table) {
+ diag("hash tables after shallow copy are identical!");
+ return 0;
+ }
+ uint i;
+ if (hashsize(from->table->table_size_exp) !=
+ hashsize(to->table->table_size_exp)) {
+ diag("hash tables after shallow copy error!");
+ return 0;
+ }
+
+ if (from->table->table_count != to->table->table_count) {
+ diag("hash tables after shallow copy error!");
+ return 0;
+ }
+
+ for (uint t = 0; t < from->table->table_count; ++t) {
+ for (i = 0; i <
+ hashsize(from->table->table_size_exp); i++) {
+ if (from->table->tables[t][i] == NULL) {
+ if (to->table->tables[t][i] != NULL) {
+ diag("hash table item error");
+ }
+ continue;
+ }
+ if ((from->table->tables[t])[i]->key_length !=
+ (to->table->tables[t])[i]->key_length) {
+ diag("hash table key lengths error!");
+ return 0;
+ }
+ if ((from->table->tables[t])[i]->key !=
+ (to->table->tables[t])[i]->key) {
+ diag("hash table key error!");
+ return 0;
+ }
+ if ((from->table->tables[t])[i]->value !=
+ (to->table->tables[t])[i]->value) {
+ diag("hash table value error!");
+ return 0;
+ }
+ }
+ }
+
+ ck_stash_item_t *item1 = from->table->stash;
+ ck_stash_item_t *item2 = to->table->stash;
+ while (item1 != NULL && item2 != NULL) {
+ if (item1->item->key_length !=
+ item2->item->key_length) {
+ diag("hash stash key length error!");
+ return 0;
+ }
+ if (item1->item->key != item2->item->key) {
+ diag("hash stash key error!");
+ return 0;
+ }
+ if (item1->item->value != item2->item->value) {
+ diag("hash stash value error!");
+ return 0;
+ }
+
+ item1 = item1->next;
+ item2 = item2->next;
+ }
+ } else {
+ if (to->table) {
+ diag("Hash table is not set to NULL "
+ "after shallow copy!");
+ errors++;
+ }
+ }
+#endif
+
+// knot_zone_deep_free(&from_zone, 0);
+// knot_zone_contents_free(&to);
+ return (errors == 0);
+
+}
+
+//static int test_zone_free(knot_zone_t **zone)
+//{
+// knot_zone_tree_apply_postorder(*zone,
+// test_zone_destroy_node_from_tree,
+// NULL);
+// knot_zone_nsec3_apply_postorder(*zone,
+// test_zone_destroy_node_from_tree,
+// NULL);
+// knot_zone_free(zone);
+// return (*zone == NULL);
+//}
+
+static const int KNOT_ZONE_TEST_COUNT = 10;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_zone_tests_count(int argc, char *argv[])
+{
+ return KNOT_ZONE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_zone_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 0;
+
+ knot_zone_contents_t *zone = NULL;
+
+ ok((res = test_zone_create(&zone)), "zone: create");
+ res_final *= res;
+
+ skip(!res, 6);
+
+ ok((res = test_zone_add_node(zone, 0)), "zone: add node");
+ res_final *= res;
+
+ skip(!res, 2);
+
+ ok((res = test_zone_get_node(zone, 0)), "zone: get node");
+ res_final *= res;
+
+ skip(!res, 1);
+
+ ok((res = test_zone_find_node(zone, 0)), "zone: find node");
+ res_final *= res;
+
+ endskip; // get node failed
+
+ endskip; // add node failed
+
+ ok((res = test_zone_add_node(zone, 1)), "zone: add nsec3 node");
+ res_final *= res;
+
+ skip(!res, 2);
+
+ ok((res = test_zone_get_node(zone, 1)), "zone: get nsec3 node");
+ res_final *= res;
+
+ skip(!res, 1);
+
+ ok((res = test_zone_find_node(zone, 1)), "zone: find nsec3 node");
+ res_final *= res;
+
+ endskip; // get nsec3 node failed
+
+ endskip; // add nsec3 node failed
+
+ ok(res = test_zone_traversals(zone), "zone: traversals");
+ res_final *= res;
+
+ ok((res = test_zone_shallow_copy()), "zone: shallow copy");
+ res_final *= res;
+
+// ok((res = test_zone_free(&zone)), "zone: free");
+// res_final *= res;
+
+ endskip; // create failed
+
+ return res_final;
+}
diff --git a/src/tests/libknot/libknot/zone_tests.h b/src/tests/libknot/libknot/zone_tests.h
new file mode 100644
index 0000000..5539709
--- /dev/null
+++ b/src/tests/libknot/libknot/zone_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_ZONE_TESTS_H_
+#define _KNOTD_ZONE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zone_tests_api;
+
+#endif /* _KNOTD_ZONE_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/zone_tree_tests.c b/src/tests/libknot/libknot/zone_tree_tests.c
new file mode 100644
index 0000000..c26746e
--- /dev/null
+++ b/src/tests/libknot/libknot/zone_tree_tests.c
@@ -0,0 +1,758 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include "tests/libknot/libknot/zone_tree_tests.h"
+#include "libknot/zone/zone-tree.h"
+#include "libknot/util/error.h"
+
+static int knot_zone_tree_tests_count(int argc, char *argv[]);
+static int knot_zone_tree_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zone_tree_tests_api = {
+ "DNS library - zone tree", //! Unit name
+ &knot_zone_tree_tests_count, //! Count scheduled tests
+ &knot_zone_tree_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+static int test_tree_init()
+{
+ int errors = 0;
+ int lived = 0;
+
+ lives_ok({
+ if (knot_zone_tree_init(NULL) != KNOT_EBADARG) {
+ diag("Calling knot_zone_tree_init with NULL "
+ "tree did not return KNOT_EBADARG!");
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: init NULL tests");
+ errors += lived != 1;
+
+ return (errors == 0);
+}
+
+static int test_tree_insert()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+ knot_node_t *node =
+ knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz."),
+ NULL),
+ NULL, 0);
+ assert(node);
+
+ lives_ok({
+ if (knot_zone_tree_insert(NULL, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_insert(tree, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_insert(NULL, node) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: insert NULL tests");
+ if (errors) {
+ diag("Zone tree insert did not return KNOT_EBADARG "
+ "when given wrong arguments");
+ }
+ errors += lived != 1;
+
+ if (knot_zone_tree_insert(tree, node) != KNOT_EOK) {
+ diag("Calling zone tree insert with valid arguments "
+ "did not return KNOT_EOK");
+ errors++;
+ }
+
+ /* Sorting will be tested in traversal functions. */
+ return (errors == 0);
+}
+
+static int test_tree_finding()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+ const knot_node_t *node =
+ knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz."),
+ NULL),
+ NULL, 0);
+ assert(node);
+
+ lives_ok({
+ if (knot_zone_tree_find(NULL, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find(tree, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find(tree, node->owner,
+ NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ const knot_node_t *found_node = NULL;
+ lived = 0;
+ if (knot_zone_tree_find(NULL, node->owner,
+ &found_node) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find(tree, NULL,
+ &found_node) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: find NULL tests");
+ if (errors) {
+ diag("Zone tree find did not return KNOT_EBADARG "
+ "when given wrong arguments");
+ }
+
+ errors += lived != 1;
+
+ /* Insert node */
+ assert(knot_zone_tree_insert(tree, (knot_node_t *)node) == KNOT_EOK);
+
+ knot_node_t *found_node = NULL;
+ if (knot_zone_tree_find(tree, node->owner,
+ (const knot_node_t **)&found_node) !=
+ KNOT_EOK) {
+ diag("Calling zone tree find with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree find did not return right node");
+ errors++;
+ }
+
+ if (knot_zone_tree_get(tree, node->owner, &found_node) !=
+ KNOT_EOK) {
+ diag("Calling zone tree get with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree get did not return right node");
+ errors++;
+ }
+
+ /* Try to search for node not in tree. */
+ knot_dname_t *alien_dname =
+ knot_dname_new_from_str("this.name.is.not.in.the.tree.",
+ strlen("this.name.is.not.in.the.tree."),
+ NULL);
+
+ if (knot_zone_tree_find(tree, alien_dname,
+ (const knot_node_t **)&found_node) !=
+ KNOT_EOK) {
+ diag("Calling zone tree find with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != NULL) {
+ diag("Zone tree find returned node that was not in the tree!");
+ errors++;
+ }
+
+ if (knot_zone_tree_get(tree, alien_dname, &found_node) !=
+ KNOT_EOK) {
+ diag("Calling zone tree get with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != NULL) {
+ diag("Zone tree get returned node that was not in the tree!");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_tree_finding_less_or_equal()
+{
+ diag("Issue nr.: 1145");
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+ const knot_node_t *node =
+ knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz"),
+ NULL),
+ NULL, 0);
+ assert(node);
+
+ lives_ok({
+ if (knot_zone_tree_find_less_or_equal(NULL,
+ NULL,
+ NULL,
+ NULL, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find_less_or_equal(tree, NULL,
+ NULL, NULL, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_find_less_or_equal(tree,
+ node->owner,
+ NULL,
+ NULL, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ const knot_node_t *found_node = NULL;
+ lived = 0;
+ if (knot_zone_tree_find_less_or_equal(NULL, node->owner,
+ &found_node, NULL, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ const knot_node_t *previous_node = NULL;
+ lived = 0;
+ if (knot_zone_tree_find_less_or_equal(tree, NULL,
+ &found_node,
+ &previous_node, 0) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: tree find less or equal NULL tests");
+ if (errors) {
+ diag("Zone tree find did not return KNOT_EBADARG "
+ "when given wrong arguments");
+ }
+
+ if (!lived) {
+ errors++;
+ }
+
+ const knot_node_t *previous_node = NULL;
+
+ /* Insert node - exact match. */
+ assert(knot_zone_tree_insert(tree, (knot_node_t *)node) == KNOT_EOK);
+
+
+ const knot_node_t *found_node = NULL;
+ if (knot_zone_tree_find_less_or_equal(tree,
+ node->owner,
+ &found_node,
+ &previous_node, 0) <= 0) {
+ diag("Calling zone tree find less with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree find did not return right node");
+ errors++;
+ }
+
+ if (knot_zone_tree_get_less_or_equal(tree, node->owner,
+ (knot_node_t **)&found_node,
+ (knot_node_t **)&previous_node, 0) <=
+ 0) {
+ diag("Calling zone tree get less with valid arguments did "
+ "not return KNOT_EOK");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree get less did not return right node");
+ errors++;
+ }
+
+ knot_dname_t *less_dname =
+ knot_dname_new_from_str("ns.nic.cz.",
+ strlen("ns.nic.cz."),
+ NULL);
+
+ assert(knot_dname_compare(less_dname, node->owner) < 0);
+
+ if (knot_zone_tree_find_less_or_equal(tree,
+ less_dname,
+ &found_node,
+ &previous_node, 0) <= 0) {
+ diag("Calling zone tree find less or equal "
+ "with valid arguments did "
+ "not return > 0");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree find less or equal did not return right node");
+ errors++;
+ }
+
+ if (knot_zone_tree_get_less_or_equal(tree, less_dname,
+ (knot_node_t **)&found_node,
+ (knot_node_t **)&previous_node, 0) <=
+ 0) {
+ diag("Calling zone tree less or equal with valid arguments did "
+ "not return > 0");
+ errors++;
+ }
+
+ if (found_node != node) {
+ diag("Zone tree get less or equal did not return right node");
+ errors++;
+ }
+
+ /* Try to search for node not in tree. */
+ knot_dname_t *alien_dname =
+ knot_dname_new_from_str("this.name.is.not.in.the.tree.",
+ strlen("this.name.is.not.in.the.tree."),
+ NULL);
+
+ if (knot_zone_tree_find_less_or_equal(tree, alien_dname,
+ &found_node,
+ &previous_node, 0) !=
+ 0) {
+ diag("Calling zone tree find less with valid arguments did "
+ "not return 0");
+ errors++;
+ }
+
+ if (knot_zone_tree_get_less_or_equal(tree,
+ alien_dname,
+ (knot_node_t **)&found_node,
+ (knot_node_t **)&previous_node, 0) !=
+ 0) {
+ diag("Calling zone tree get with valid arguments did "
+ "not return 0");
+ errors++;
+ }
+
+ /* Set node previous label. */
+ knot_node_t *tmp_node =
+ knot_node_new(knot_dname_new_from_str("ns.nic.cz.",
+ strlen("ns.nic.cz"),
+ NULL), NULL, 0);
+ assert(tmp_node);
+ knot_node_set_parent((knot_node_t *)node, tmp_node);
+
+ if (knot_zone_tree_find_less_or_equal(tree, node->owner,
+ &found_node,
+ &previous_node, 0) <=
+ 0) {
+ diag("Calling zone tree find with valid arguments did "
+ "not return > 0");
+ errors++;
+ }
+
+ if (found_node != node || previous_node != tmp_node) {
+ diag("Zone tree find did not return valid nodes!");
+ errors++;
+ }
+
+
+ if (knot_zone_tree_get_less_or_equal(tree, node->owner,
+ (knot_node_t **)&found_node,
+ (knot_node_t **)&previous_node, 0) <=
+ 0) {
+ diag("Calling zone tree get with valid arguments did "
+ "not return > 0");
+ errors++;
+ }
+
+ if (found_node != node || previous_node != tmp_node) {
+ diag("Zone get find did not return valid nodes!");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_tree_remove()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+ knot_node_t *node =
+ knot_node_new(knot_dname_new_from_str("a.ns.nic.cz.",
+ strlen("a.ns.nic.cz"),
+ NULL),
+ NULL, 0);
+ assert(node);
+
+ /* Add node. */
+ int ret = knot_zone_tree_insert(tree, node);
+ assert(ret == 0);
+ assert(ret == 0);
+
+ lives_ok({
+ if (knot_zone_tree_remove(NULL, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_remove(tree, NULL, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_remove(tree, node->owner, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_remove(NULL, node->owner, NULL) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ knot_zone_tree_node_t *deleted_node = NULL;
+ lived = 0;
+ if (knot_zone_tree_remove(NULL, node->owner, &deleted_node) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_remove(tree, NULL, &deleted_node) !=
+ KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: remove NULL tests");
+ if (errors) {
+ diag("Zone tree remove did not return KNOT_EBADARG "
+ "when given wrong arguments");
+ }
+
+ errors += lived != 1;
+
+ knot_zone_tree_node_t *removed_node = NULL;
+
+ /* Remove previously inserted node. */
+ if (knot_zone_tree_remove(tree, node->owner, &removed_node) !=
+ KNOT_EOK) {
+ diag("Could not remove previously inserted node!");
+ errors++;
+ }
+
+ if (removed_node == NULL || removed_node->node != node) {
+ diag("Wrong node was removed!");
+ errors++;
+ }
+
+ /*
+ * Try remove the node again - it should not be there and
+ * removed_node should be NULL.
+ */
+
+ if (knot_zone_tree_remove(tree, node->owner, &removed_node) !=
+ KNOT_EOK) {
+ diag("Could not remove previously inserted node!");
+ errors++;
+ }
+
+ if (removed_node != NULL) {
+ diag("Zone tree remove returned previously removed node!");
+ errors++;
+ }
+
+ return (errors == 0);
+
+}
+
+struct test_zone_tree_args {
+ knot_node_t *array[10 * 1024];
+ size_t count;
+};
+
+static void add_to_array(knot_zone_tree_node_t *node, void *data)
+{
+ struct test_zone_tree_args *args =
+ (struct test_zone_tree_args *)data;
+ args->array[args->count++] = node->node;
+}
+
+static int test_traversal(knot_node_t **nodes,
+ size_t node_count,
+ uint code)
+{
+ int errors = 0;
+ int lived = 0;
+
+ int (*trav_func)(knot_zone_tree_t *,
+ void (*)(knot_zone_tree_node_t *, void *),
+ void *);
+
+ trav_func = (code) ? knot_zone_tree_reverse_apply_inorder :
+ knot_zone_tree_forward_apply_inorder;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+
+ lives_ok({
+ if (trav_func(NULL, NULL, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (trav_func(tree, NULL, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (trav_func(NULL, add_to_array, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: traversal NULL tests");
+
+ if (errors) {
+ diag("Traversal function did not return KNOT_EBADARG "
+ "when given NULL parameters");
+ }
+
+ errors += lived != 1;
+
+ /* Add nodes to tree. */
+ for (int i = 0; i < node_count; i++) {
+ assert(knot_zone_tree_insert(tree, nodes[i]) == KNOT_EOK);
+ }
+
+ struct test_zone_tree_args args;
+ args.count = 0;
+
+ trav_func(tree, add_to_array, &args);
+
+ if (args.count != node_count) {
+ diag("Traversal function traversed more nodes than it "
+ "should have!");
+ return ++errors;
+ }
+
+ for (int i = 0; i < node_count; i++) {
+ int match = nodes[i] == args.array[i];
+ if (!match) {
+ diag("Traversal function returned nodes in wrong "
+ "order!");
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+static int test_tree_traversals()
+{
+ /*!< \todo I can test inorder and reverse inorder, but I don't know
+ * how to test others. It is somehow tested in zone tests. */
+ int errors = 0;
+
+ /* Create few nodes. (5 should be enough) */
+ knot_node_t *nodes[5];
+ for (int i = 0; i < 5; i++) {
+ char owner_string[20];
+ owner_string[0] = i + '0';
+ memcpy(owner_string + 1, ".ns.test.cz.",
+ strlen(".ns.test.cz.") + 1);
+ nodes[i] =
+ knot_node_new(knot_dname_new_from_str(owner_string,
+ strlen(owner_string),
+ NULL), NULL, 0);
+ }
+
+ if (test_traversal(nodes, 5, 0)) {
+ diag("Inorder traversal failed");
+ errors++;
+ }
+
+ for (int i = 0; i < 5; i++) {
+ char owner_string[20];
+ owner_string[0] = (5 - i) + '0';
+ memcpy(owner_string + 1, ".ns.test.cz.",
+ strlen(".ns.test.cz.") + 1);
+ nodes[i] =
+ knot_node_new(knot_dname_new_from_str(owner_string,
+ strlen(owner_string),
+ NULL), NULL, 0);
+ }
+
+ if (test_traversal(nodes, 5, 1)) {
+ diag("Reverse inorder traversal failed");
+ errors++;
+ }
+
+ return (errors == 0);
+}
+
+static int test_tree_shallow_copy()
+{
+ int errors = 0;
+ int lived = 0;
+
+ knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t));
+ assert(tree);
+ knot_zone_tree_init(tree);
+
+ lives_ok({
+ if (knot_zone_tree_shallow_copy(NULL, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_shallow_copy(tree, NULL) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ lived = 0;
+ if (knot_zone_tree_shallow_copy(NULL, tree) != KNOT_EBADARG) {
+ errors++;
+ }
+ lived = 1;
+ }, "zone tree: shallow copy NULL tests");
+ if (errors) {
+ diag("Zone tree shallow copy did not return KNOT_EBADARG when "
+ "given NULL arguments");
+ }
+ errors += lived != 1;
+
+ /* Create few nodes. (5 should be enough) */
+ knot_node_t *nodes[5];
+ for (int i = 0; i < 5; i++) {
+ char owner_string[20];
+ owner_string[0] = i + '0';
+ memcpy(owner_string + 1, ".ns.test.cz.",
+ strlen(".ns.test.cz.") + 1);
+ nodes[i] =
+ knot_node_new(knot_dname_new_from_str(owner_string,
+ strlen(owner_string),
+ NULL), NULL, 0);
+ /* Insert node to tree. */
+ assert(knot_zone_tree_insert(tree, nodes[i]) == KNOT_EOK);
+ }
+
+ /* Create shallow copy. */
+ knot_zone_tree_t *new_tree = malloc(sizeof(knot_zone_tree_t));
+ assert(new_tree);
+ knot_zone_tree_init(new_tree);
+
+ if (knot_zone_tree_shallow_copy(tree, new_tree) != KNOT_EOK) {
+ diag("Zone tree shallow copy did not return KNOT_EOK "
+ "when executed with valid parameters");
+ return 0;
+ }
+
+ /* Traverse the tree twice and check that arrays are the same. */
+ struct test_zone_tree_args args1;
+ args1.count = 0;
+
+ knot_zone_tree_forward_apply_inorder(tree, add_to_array,
+ &args1);
+
+
+ struct test_zone_tree_args args2;
+ args2.count = 0;
+ knot_zone_tree_forward_apply_inorder(new_tree, add_to_array,
+ &args2);
+
+ if (args1.count != args2.count) {
+ diag("Zone tree created by shallow copy has wrong count"
+ "of nodes");
+ return 0;
+ }
+
+ for (int i = 0; i < args1.count; i++) {
+ if (args1.array[i] != args2.array[i]) {
+ diag("Zone tree created by shallow copy has wrong "
+ "nodes");
+ errors++;
+ }
+ }
+
+ return (errors == 0);
+
+}
+
+
+static const int KNOT_ZONE_TREE_TEST_COUNT = 14;
+
+static int knot_zone_tree_tests_count(int argc, char *argv[])
+{
+ return KNOT_ZONE_TREE_TEST_COUNT;
+}
+
+static int knot_zone_tree_tests_run(int argc, char *argv[])
+{
+ ok(test_tree_init(), "zone tree: init");
+ ok(test_tree_insert(), "zone tree: insertion");
+ ok(test_tree_finding(), "zone tree: finding");
+ todo();
+ ok(test_tree_finding_less_or_equal(), "zone tree: find less or equal");
+ endtodo;
+ ok(test_tree_remove(), "zone tree: removal");
+ ok(test_tree_traversals(), "zone tree: traversals");
+ ok(test_tree_shallow_copy(), "zone tree: shallow copy");
+
+ return 1;
+}
diff --git a/src/tests/libknot/libknot/zone_tree_tests.h b/src/tests/libknot/libknot/zone_tree_tests.h
new file mode 100644
index 0000000..4cea88c
--- /dev/null
+++ b/src/tests/libknot/libknot/zone_tree_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTDZONE_TREE_TESTS_H_
+#define _KNOTDZONE_TREE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zone_tree_tests_api;
+
+#endif /* _KNOTDZONE_TREE_TESTS_H_ */
diff --git a/src/tests/libknot/libknot/zonedb_tests.c b/src/tests/libknot/libknot/zonedb_tests.c
new file mode 100644
index 0000000..7b45587
--- /dev/null
+++ b/src/tests/libknot/libknot/zonedb_tests.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tests/libknot/libknot/zonedb_tests.h"
+
+
+static int zonedb_tests_count(int argc, char *argv[]);
+static int zonedb_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zonedb_tests_api = {
+ "Zone database", //! Unit name
+ &zonedb_tests_count, //! Count scheduled tests
+ &zonedb_tests_run //! Run scheduled tests
+};
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int zonedb_tests_count(int argc, char *argv[])
+{
+ return 0;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int zonedb_tests_run(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/src/tests/libknot/libknot/zonedb_tests.h b/src/tests/libknot/libknot/zonedb_tests.h
new file mode 100644
index 0000000..0c4f8ef
--- /dev/null
+++ b/src/tests/libknot/libknot/zonedb_tests.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_ZONEDB_TESTS_H_
+#define _KNOTD_ZONEDB_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zonedb_tests_api;
+
+#endif /* _KNOTD_ZONEDB_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/files/parsed_data b/src/tests/libknot/realdata/files/parsed_data
new file mode 100644
index 0000000..fe22b90
--- /dev/null
+++ b/src/tests/libknot/realdata/files/parsed_data
Binary files differ
diff --git a/src/tests/libknot/realdata/files/parsed_data_queries b/src/tests/libknot/realdata/files/parsed_data_queries
new file mode 100644
index 0000000..5857c87
--- /dev/null
+++ b/src/tests/libknot/realdata/files/parsed_data_queries
Binary files differ
diff --git a/src/tests/libknot/realdata/files/raw_data b/src/tests/libknot/realdata/files/raw_data
new file mode 100644
index 0000000..502005e
--- /dev/null
+++ b/src/tests/libknot/realdata/files/raw_data
Binary files differ
diff --git a/src/tests/libknot/realdata/files/raw_data_queries b/src/tests/libknot/realdata/files/raw_data_queries
new file mode 100644
index 0000000..9062d5a
--- /dev/null
+++ b/src/tests/libknot/realdata/files/raw_data_queries
Binary files differ
diff --git a/src/tests/libknot/realdata/libknot/dname_tests_realdata.c b/src/tests/libknot/realdata/libknot/dname_tests_realdata.c
new file mode 100644
index 0000000..d0216c7
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/dname_tests_realdata.c
@@ -0,0 +1,411 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "tests/libknot/realdata/libknot/dname_tests_realdata.h"
+#include "libknot/dname.h"
+#include "libknot/common.h"
+
+#include "common/print.h"
+#include "common/lists.h"
+
+static int knot_dname_tests_count(int argc, char *argv[]);
+static int knot_dname_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api dname_tests_api = {
+ "DNS library - dname", //! Unit name
+ &knot_dname_tests_count, //! Count scheduled tests
+ &knot_dname_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+int check_domain_name(const knot_dname_t *dname,
+ const test_dname_t *test_dname)
+{
+ int errors = 0;
+
+ if (dname == NULL) {
+ diag("Domain name not created!");
+ return 1;
+ }
+
+// diag("test_dname: %p, dname: %p", test_dname, dname);
+ // check size
+ if (knot_dname_size(dname) != test_dname->size) {
+ diag("Bad size of the created domain name: %u (should be %u).",
+ knot_dname_size(dname), test_dname->size);
+ ++errors;
+ } else {
+ // check wire format
+ uint size = knot_dname_size(dname);
+ if (strncmp((char *)knot_dname_name(dname),
+ (char *)test_dname->wire, size) != 0) {
+ diag("The wire format of the created "
+ "domain name is wrong:"
+ " '%.*s' (should be '%.*s').",
+ size, knot_dname_name(dname),
+ size, test_dname->wire);
+ ++errors;
+ }
+ }
+ // check labels
+ if (test_dname->label_count != dname->label_count) {
+ diag("Label count of the created domain name is wrong:"
+ " %d (should be %d)\n", dname->label_count,
+ test_dname->label_count);
+ ++errors;
+ }
+ if (strncmp((char *)dname->labels, (char *)test_dname->labels,
+ test_dname->label_count) != 0) {
+ diag("Label offsets of the created domain name are wrong.\n");
+ hex_print((char *)dname->labels, test_dname->label_count);
+ hex_print((char *)test_dname->labels, test_dname->label_count);
+ ++errors;
+ }
+
+ return errors;
+}
+
+static int test_dname_create_from_str(const list *dname_list)
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ /* Test with real data. */
+ node *n = NULL;
+ WALK_LIST(n, *dname_list) {
+ //note("testing domain: %s", test_domains_ok[i].str);
+ test_dname_t *test_dname = (test_dname_t *)n;
+ dname = knot_dname_new_from_str(test_dname->str,
+ strlen(test_dname->str), NULL);
+ errors += check_domain_name(dname, test_dname);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_create_from_wire(const list *dname_list)
+{
+ int errors = 0;
+ knot_dname_t *dname = NULL;
+
+ node *n = NULL;
+ WALK_LIST(n, *dname_list) {
+ test_dname_t *test_dname = (test_dname_t *)n;
+ dname = knot_dname_new_from_wire(test_dname->wire,
+ test_dname->size, NULL);
+ errors += check_domain_name(dname, test_dname);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_to_str(const list *dname_list)
+{
+ int errors = 0;
+
+ /*
+ * Converts dname wireformat to string represenation, which is compared
+ * with entries in test_domains structure.
+ */
+
+ knot_dname_t *dname = NULL;
+
+ /* Test with real data. */
+ node *n = NULL;
+ WALK_LIST(n, *dname_list) {
+ //note("testing domain: %s", test_domains_ok[i].str);
+ test_dname_t *test_dname = (test_dname_t *)n;
+ dname = knot_dname_new_from_wire(
+ test_dname->wire,
+ test_dname->size,
+ NULL);
+ if (dname == NULL) {
+ ERR_ALLOC_FAILED;
+ return 0;
+ }
+
+ char *name_str = knot_dname_to_str(dname);
+ if (strcmp(name_str, test_dname->str) != 0) {
+ diag("Presentation format of domain name wrong:"
+ " %s (should be %s)",
+ name_str, test_dname->str);
+ ++errors;
+ }
+ free(name_str);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+static int test_dname_is_fqdn(const list *dname_list)
+{
+ int errors = 0;
+
+ knot_dname_t *dname;
+
+ /* All dnames from real data are fqdn */
+
+ node *n = NULL;
+ WALK_LIST(n, *dname_list) {
+ test_dname_t *test_dname = (test_dname_t *)n;
+ dname = knot_dname_new_from_wire(test_dname->wire,
+ test_dname->size, NULL);
+ errors += !knot_dname_is_fqdn(dname);
+ knot_dname_free(&dname);
+ }
+
+ return (errors == 0);
+}
+
+//static int check_wires(const uint8_t *wire1, uint size1,
+// uint8_t *wire2, uint size2)
+//{
+// if (size1 != size2) {
+// return 0;
+// }
+
+// int i;
+
+// for (i = 0; (i < size1); i++) {
+// if (wire1[i] != wire2[i]) {
+// return 0;
+// }
+// }
+
+// return 1;
+//}
+
+///* \note not to be run separately */
+//static int test_dname_name(knot_dname_t **dnames_fqdn,
+// knot_dname_t **dnames_non_fqdn)
+//{
+// assert(dnames_fqdn);
+// assert(dnames_non_fqdn);
+
+// int errors = 0;
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// const uint8_t *tmp_name;
+// tmp_name = knot_dname_name(dnames_fqdn[i]);
+// if (!check_wires(tmp_name, dnames_fqdn[i]->size,
+// (uint8_t *)test_domains_ok[i].wire,
+// test_domains_ok[i].size)) {
+// diag("Got bad name value from structure: "
+// "%s, should be: %s",
+// tmp_name, test_domains_ok[i].wire);
+// errors++;
+// }
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// const uint8_t *tmp_name;
+// tmp_name = knot_dname_name(dnames_non_fqdn[i]);
+// if (!check_wires(tmp_name, dnames_non_fqdn[i]->size,
+// (uint8_t *)test_domains_non_fqdn[i].wire,
+// test_domains_non_fqdn[i].size)) {
+// diag("Got bad name value from structure: "
+// "%s, should be: %s",
+// tmp_name, test_domains_non_fqdn[i].wire);
+// errors++;
+// }
+// }
+
+// return errors;
+//}
+
+///* \note not to be run separately */
+//static int test_dname_size(knot_dname_t **dnames_fqdn,
+// knot_dname_t **dnames_non_fqdn)
+//{
+// assert(dnames_fqdn);
+// assert(dnames_non_fqdn);
+
+// int errors = 0;
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// uint8_t tmp_size;
+// if ((tmp_size = knot_dname_size(dnames_fqdn[i])) !=
+// test_domains_ok[i].size) {
+// diag("Got bad size value from structure: "
+// "%u, should be: %u",
+// tmp_size, test_domains_ok[i].size);
+// errors++;
+// }
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// uint8_t tmp_size;
+// if ((tmp_size = knot_dname_size(dnames_non_fqdn[i])) !=
+// test_domains_non_fqdn[i].size) {
+// diag("Got bad size value from structure: "
+// "%u, should be: %u",
+// tmp_size, test_domains_non_fqdn[i].size);
+// errors++;
+// }
+// }
+
+// return errors;
+//}
+
+///* \note not to be run separately */
+//static int test_dname_node(knot_dname_t **dnames_fqdn,
+// knot_dname_t **dnames_non_fqdn)
+//{
+// assert(dnames_fqdn);
+// assert(dnames_non_fqdn);
+
+// int errors = 0;
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// const knot_node_t *tmp_node;
+// if ((tmp_node = knot_dname_node(dnames_fqdn[i])) !=
+// NODE_ADDRESS) {
+// diag("Got bad node value from structure: "
+// "%p, should be: %p",
+// tmp_node, NODE_ADDRESS);
+// errors++;
+// }
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// const knot_node_t *tmp_node;
+// if ((tmp_node = knot_dname_node(dnames_non_fqdn[i])) !=
+// NODE_ADDRESS) {
+// diag("Got bad node value from structure: "
+// "%s, should be: %s",
+// tmp_node, NODE_ADDRESS);
+// errors++;
+// }
+// }
+
+// return errors;
+//}
+
+//static int test_dname_getters(uint type)
+//{
+// int errors = 0;
+
+// knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK];
+// knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN];
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// dnames_fqdn[i] = knot_dname_new_from_wire(
+// (uint8_t *)test_domains_ok[i].wire,
+// test_domains_ok[i].size, NODE_ADDRESS);
+// assert(dnames_fqdn[i] != NULL);
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// dnames_non_fqdn[i] = knot_dname_new_from_wire(
+// (uint8_t *)test_domains_non_fqdn[i].wire,
+// test_domains_non_fqdn[i].size, NODE_ADDRESS);
+// assert(dnames_non_fqdn[i] != NULL);
+// }
+
+// switch (type) {
+// case 0: {
+// errors += test_dname_name(dnames_fqdn, dnames_non_fqdn);
+// break;
+// }
+
+// case 1: {
+// errors += test_dname_size(dnames_fqdn, dnames_non_fqdn);
+// break;
+// }
+
+// case 2: {
+// errors += test_dname_node(dnames_fqdn, dnames_non_fqdn);
+// break;
+// }
+// } /* switch */
+
+// for (int i = 0; i < TEST_DOMAINS_OK; i++) {
+// knot_dname_free(&dnames_fqdn[i]);
+// }
+
+// for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) {
+// knot_dname_free(&dnames_non_fqdn[i]);
+// }
+
+// return (errors == 0);
+//}
+
+static const int KNOT_DNAME_TEST_COUNT = 4;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_dname_tests_count(int argc, char *argv[])
+{
+ return KNOT_DNAME_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_dname_tests_run(int argc, char *argv[])
+{
+ const test_data_t *data = data_for_knot_tests;
+
+ int res = 0,
+ res_str = 0,
+ res_wire = 0,
+ res_str_non_fqdn = 0,
+ res_final = 1;
+
+ ok((res_str = test_dname_create_from_str(&data->dname_list)),
+ "dname: create from string");
+ ok((res_wire = test_dname_create_from_wire(&data->dname_list)),
+ "dname: create from wire");
+
+ res_final *= res_str;
+ res_final *= res_wire;
+ res_final *= res_str_non_fqdn;
+
+// res = test_dname_getters(0);
+// ok(res, "dname: name");
+
+// res = test_dname_getters(1);
+// ok(res, "dname: size");
+
+// res = test_dname_getters(2);
+// ok(res, "dname: node");
+
+// skip(!res_str || !res_wire || !res_str_non_fqdn, 2);
+
+ ok((res = test_dname_to_str(&data->dname_list)),
+ "dname: convert to str");
+ res_final *= res;
+
+// endskip; /* !res_str || !res_wire */
+
+ ok((res = test_dname_is_fqdn(&data->dname_list)), "dname: fqdn");
+ res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/dname_tests_realdata.h b/src/tests/libknot/realdata/libknot/dname_tests_realdata.h
new file mode 100644
index 0000000..a7d75aa
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/dname_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_DNAME_TESTS_H_
+#define _KNOTD_DNAME_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api dname_tests_api;
+
+#endif /* _KNOTD_DNAME_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/edns_tests_realdata.c b/src/tests/libknot/realdata/libknot/edns_tests_realdata.c
new file mode 100644
index 0000000..257d480
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/edns_tests_realdata.c
@@ -0,0 +1,563 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "tests/libknot/realdata/libknot/edns_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/common.h"
+#include "libknot/edns.h"
+
+static int knot_edns_tests_count(int argc, char *argv[]);
+static int knot_edns_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api edns_tests_api = {
+ "DNS library - EDNS", //! Unit name
+ &knot_edns_tests_count, //! Count scheduled tests
+ &knot_edns_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+///* Creates actual knot_opt_rr_t variable from test_edns_t variable */
+//static knot_opt_rr_t *opt_rr_from_test_edns(test_edns_t *test_edns)
+//{
+// knot_opt_rr_t *ret = knot_edns_new();
+
+// CHECK_ALLOC_LOG(ret, NULL);
+
+// ret->flags = test_edns->flags;
+// ret->ext_rcode = test_edns->ext_rcode;
+// ret->payload = test_edns->payload;
+// ret->version = test_edns->version;
+
+// for (int i = 0; i < test_edns->option_count; i++) {
+// if (knot_edns_add_option(ret, test_edns->options[i].code,
+// test_edns->options[i].length,
+// test_edns->options[i].data) != 0) {
+// knot_edns_free(&ret);
+// return NULL;
+// }
+// }
+
+// return ret;
+//}
+
+///* simple wire compare - 0 if same, 1 otherwise */
+//static int edns_compare_wires(uint8_t *wire1,
+// uint8_t *wire2,
+// uint16_t length)
+//{
+// for (uint i = 0; i < length; i++) {
+// if (wire1[i] != wire2[i]) {
+// return 1;
+// }
+// }
+
+// return 0;
+//}
+
+//static int check_edns(const knot_opt_rr_t *edns,
+// const test_edns_t *test_edns)
+//{
+// if (edns->option_count != test_edns->option_count) {
+// diag("Option count is wrong");
+// return -1;
+// }
+
+// for (int i = 0; i < edns->option_count; i++) {
+// /* check options */
+// if (edns->options[i].code != test_edns->options[i].code) {
+// diag("Code in options is wrong");
+// return -1;
+// }
+
+// if (edns->options[i].length != test_edns->options[i].length) {
+// diag("Length in options is wrong");
+// return -1;
+// }
+
+// if (edns_compare_wires(edns->options[i].data,
+// test_edns->options[i].data,
+// edns->options[i].length) != 0) {
+// diag("Data in options are wrong");
+// return -1;
+// }
+// }
+
+// if (edns->version != test_edns->version) {
+// diag("Version is wrong");
+// return -1;
+// }
+
+// if (edns->flags != test_edns->flags) {
+// diag("Flags are wrong");
+// return -1;
+// }
+
+// if (edns->size != test_edns->size) {
+// diag("Size is wrong");
+// return -1;
+// }
+
+// return 0;
+//}
+
+//static int test_edns_get_payload(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_get_payload(edns) !=
+// test_edns->payload) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_get_ext_rcode(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_get_ext_rcode(edns) !=
+// test_edns->ext_rcode) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_get_flags(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_get_flags(edns) !=
+// test_edns->flags) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_get_version(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_get_version(edns) !=
+// test_edns->version) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_do(const knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// if (knot_edns_do(edns) !=
+// (test_edns->flags & KNOT_EDNS_DO_MASK)) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_size(knot_opt_rr_t *edns, test_edns_t *test_edns)
+//{
+// diag("%d %d\n", edns->size, test_edns->size);
+// if (knot_edns_size(edns) !=
+// test_edns->size) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_set_payload(knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// knot_edns_set_payload(edns, test_edns->payload);
+
+// if (edns->payload !=
+// test_edns->payload) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_set_ext_rcode(knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// knot_edns_set_ext_rcode(edns, test_edns->ext_rcode);
+// if (edns->ext_rcode !=
+// test_edns->ext_rcode) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_set_version(knot_opt_rr_t *edns,
+// test_edns_t *test_edns)
+//{
+// knot_edns_set_version(edns,
+// test_edns->version);
+
+// if (edns->version !=
+// test_edns->version) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_set_do(knot_opt_rr_t *edns)
+//{
+// knot_edns_set_do(edns);
+
+// if (!knot_edns_do(edns)) {
+// return 0;
+// } else {
+// return 1;
+// }
+//}
+
+//static int test_edns_getters(uint type)
+//{
+// int errors = 0;
+// for (int i = 0; i < TEST_EDNS; i++) {
+// knot_opt_rr_t *edns =
+// opt_rr_from_test_edns(&(test_edns_data[i]));
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return -1;
+// }
+
+// switch(type) {
+// case 0:
+// if (test_edns_get_payload(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong payload!");
+// errors++;
+// }
+// break;
+// case 1:
+// if (test_edns_get_ext_rcode(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong extended RCODE!");
+// errors++;
+// }
+// break;
+// case 2:
+// if (test_edns_get_flags(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong flags!");
+
+// errors++;
+// }
+// break;
+// case 3:
+// if (test_edns_get_version(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong version!");
+// errors++;
+// }
+// break;
+// case 4:
+// if (test_edns_do(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong DO bit!");
+// errors++;
+// }
+// break;
+// case 5:
+// if (test_edns_size(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Got wrong size!");
+// errors++;
+// }
+// break;
+// default:
+// diag("Unknown option");
+// errors++;
+// } /* switch */
+
+// knot_edns_free(&edns);
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_edns_setters(uint type)
+//{
+// int errors = 0;
+// for (int i = 0; i < TEST_EDNS; i++) {
+// knot_opt_rr_t *edns =
+// opt_rr_from_test_edns(&(test_edns_data[i]));
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return -1;
+// }
+
+// switch(type) {
+// case 0:
+// if (test_edns_set_payload(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Set wrong payload!");
+// errors++;
+// }
+// break;
+// case 1:
+// if (test_edns_set_ext_rcode(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Set wrong ext_rcode");
+// errors++;
+// }
+// break;
+// case 2:
+// if (test_edns_set_version(edns,
+// &test_edns_data[i]) != 1) {
+// diag("Set wrong version!");
+// errors++;
+// }
+// break;
+// case 3:
+// if (test_edns_set_do(edns) != 1) {
+// diag("Set wrong DO bit!");
+// errors++;
+// }
+// break;
+// default:
+// diag("Unknown option");
+// errors++;
+// } /* switch */
+
+// knot_edns_free(&edns);
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_edns_wire()
+//{
+// /*
+// * Tests to_wire and from_wire in one test.
+// */
+// for (int i = 0; i < TEST_EDNS; i++) {
+// /* Creates instance from test_edns_t. */
+// knot_opt_rr_t *edns =
+// opt_rr_from_test_edns(&(test_edns_data[i]));
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return -1;
+// }
+
+// uint8_t *wire = NULL;
+// wire = malloc(sizeof(uint8_t) * edns->size);
+// CHECK_ALLOC_LOG(wire, 0);
+
+// /* Converts EDNS to wire. */
+// short wire_size = knot_edns_to_wire(edns, wire, 100);
+
+// if (wire_size == -1) {
+// diag("Could not create EDNS wire");
+// return 0;
+// }
+
+// knot_opt_rr_t *edns_from_wire = knot_edns_new();
+// if (edns == NULL) {
+// return 0;
+// }
+
+// /* TODO use some constant */
+// /* Creates new EDNS from wire */
+// if (knot_edns_new_from_wire(edns_from_wire,
+// wire,
+// 100) <= 0) {
+// diag("Could not create from wire");
+// return 0;
+// }
+
+// /* Checks whether EDNS created from wire is the same */
+// if (check_edns(edns_from_wire,
+// &(test_edns_data[i])) != 0) {
+// diag("EDNS created from wire is different from the "
+// "original one");
+// }
+
+// free(wire);
+// knot_edns_free(&edns_from_wire);
+// knot_edns_free(&edns);
+// }
+// return 1;
+//}
+
+//static int test_edns_add_option()
+//{
+// /*
+// * Create empty EDNS and add options one by one, testing their presence.
+// */
+// for (int i = 0; i < TEST_EDNS; i++) {
+// knot_opt_rr_t *edns = knot_edns_new();
+// assert(edns->option_count == 0);
+
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return 0;
+// }
+
+// for (int j = 0; j < test_edns_data[i].option_count; j++) {
+// if (knot_edns_add_option(edns,
+// test_edns_data[i].options[j].code,
+// test_edns_data[i].options[j].length,
+// test_edns_data[i].options[j].
+// data) != 0) {
+// diag("Could not add option");
+// return 0;
+// }
+
+// if (edns->options[j].code !=
+// test_edns_data[i].options[j].code) {
+// diag("Option code wrongly added!");
+// return 0;
+// }
+
+// if (edns->options[j].length !=
+// test_edns_data[i].options[j].length) {
+// diag("Option length wrongly added!");
+// return 0;
+// }
+
+// if (edns_compare_wires(edns->options[j].data,
+// test_edns_data[i].
+// options[j].data,
+// edns->options[j].length) != 0) {
+// diag("Option wire wrongly added!");
+// return 0;
+// }
+// }
+// knot_edns_free(&edns);
+// }
+// return 1;
+//}
+
+//static int test_edns_has_option()
+//{
+// /*
+// * Create empty EDNS and add options one by one, testing their presence
+// */
+// for (int i = 0; i < TEST_EDNS; i++) {
+// knot_opt_rr_t *edns = knot_edns_new();
+// assert(edns->option_count == 0);
+
+// if (edns == NULL) {
+// ERR_ALLOC_FAILED;
+// return 0;
+// }
+
+// for (int j = 0; j < test_edns_data[i].option_count; j++) {
+// if (knot_edns_add_option(edns,
+// test_edns_data[i].options[j].code,
+// test_edns_data[i].options[j].length,
+// test_edns_data[i].options[j].
+// data) != 0) {
+// diag("Could not add option");
+// return 0;
+// }
+
+// if (knot_edns_has_option(edns,
+// test_edns_data[i].options[j].code) != 1) {
+// diag("Option not found!");
+// return 0;
+// }
+// }
+// knot_edns_free(&edns);
+// }
+// return 1;
+//}
+
+static const int KNOT_EDNS_TESTS_COUNT = 0;
+
+///*! This helper routine should report number of
+// * scheduled tests for given parameters.
+// */
+static int knot_edns_tests_count(int argc, char *argv[])
+{
+ return KNOT_EDNS_TESTS_COUNT;
+}
+
+///*! Run all scheduled tests for given parameters.
+// */
+static int knot_edns_tests_run(int argc, char *argv[])
+{
+// int res = 0;
+ int res_final = 1;
+
+// res = test_edns_getters(0);
+// ok(res, "EDNS: get payload");
+// res_final *= res;
+
+// res = test_edns_getters(1);
+// ok(res, "EDNS: get extenden RCODE");
+// res_final *= res;
+
+// res = test_edns_getters(2);
+// ok(res, "EDNS: get flags");
+// res_final *= res;
+
+// res = test_edns_getters(3);
+// ok(res, "EDNS: get version");
+// res_final *= res;
+
+// res = test_edns_getters(4);
+// ok(res, "EDNS: do");
+// res_final *= res;
+
+// res = test_edns_getters(5);
+// ok(res, "EDNS: size");
+// res_final *= res;
+
+// res = test_edns_setters(0);
+// ok(res, "EDNS: set payload");
+// res_final *= res;
+
+// res = test_edns_setters(1);
+// ok(res, "EDNS: set extended RCODE");
+// res_final *= res;
+
+// res = test_edns_setters(2);
+// ok(res, "EDNS: set version");
+// res_final *= res;
+
+// res = test_edns_setters(3);
+// ok(res, "EDNS: set DO");
+// res_final *= res;
+
+// res = test_edns_add_option();
+// ok(res, "EDNS: add option");
+// res_final *= res;
+
+// res = test_edns_has_option();
+// ok(res, "EDNS: has option");
+// res_final *= res;
+
+// res = test_edns_wire();
+// ok(res, "EDNS: to_wire and from_wire");
+// res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/edns_tests_realdata.h b/src/tests/libknot/realdata/libknot/edns_tests_realdata.h
new file mode 100644
index 0000000..cfa64b0
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/edns_tests_realdata.h
@@ -0,0 +1,35 @@
+/*!
+ * \file edns_tests.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * Contains unit tests for ENDS API
+ *
+ * Contains tests for:
+ * - ENDS API
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD__EDNS_TESTS_H_
+#define _KNOTD__EDNS_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api edns_tests_api;
+
+#endif /* _KNOTD__EDNS_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/node_tests_realdata.c b/src/tests/libknot/realdata/libknot/node_tests_realdata.c
new file mode 100644
index 0000000..3218c8e
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/node_tests_realdata.c
@@ -0,0 +1,385 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "tests/libknot/realdata/libknot/node_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/dname.h"
+#include "libknot/zone/node.h"
+#include "libknot/util/descriptor.h"
+
+static int knot_node_tests_count(int argc, char *argv[]);
+static int knot_node_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api node_tests_api = {
+ "DNS library - node", //! Unit name
+ &knot_node_tests_count, //! Count scheduled tests
+ &knot_node_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+/* TODO It would be wise not to name variables totally same as structures ... */
+knot_dname_t *dname_from_test_dname(const test_dname_t *test_dname)
+{
+ assert(test_dname != NULL);
+ knot_dname_t *ret = knot_dname_new_from_wire(test_dname->wire,
+ test_dname->size,
+ NULL);
+ CHECK_ALLOC(ret, NULL);
+
+ return ret;
+}
+
+static knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset)
+{
+ assert(test_rrset != NULL);
+ knot_dname_t *owner = dname_from_test_dname(test_rrset->owner);
+ CHECK_ALLOC(owner, NULL);
+
+ knot_rrset_t *ret = knot_rrset_new(owner, test_rrset->type,
+ test_rrset->rclass,
+ test_rrset->ttl);
+ if (ret == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_dname_free(&owner);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static int test_node_create(const list *node_list)
+{
+ /* Tests creation of node by comparing with test_node struct */
+ knot_node_t *tmp;
+ int errors = 0;
+
+ node *n = NULL;
+ WALK_LIST(n, *node_list) {
+ const test_node_t *tmp_node = (test_node_t *)n;
+ assert(tmp_node);
+
+ knot_dname_t *owner =
+ dname_from_test_dname(tmp_node->owner);
+ if (owner == NULL) {
+ return 0;
+ }
+ tmp = knot_node_new(owner,
+ (knot_node_t *)tmp_node->parent, 0);
+ if (tmp == NULL ||
+ (strncmp((char *)tmp->owner->name,
+ (char *)tmp_node->owner->wire,
+ tmp->owner->size) != 0) ||
+ tmp->parent != (knot_node_t *)tmp_node->parent ||
+ tmp->rrset_tree == NULL) {
+ errors++;
+ diag("Failed to create node structure");
+ }
+ knot_node_free(&tmp, 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+static int test_node_add_rrset(list *rrset_list)
+{
+ knot_node_t *tmp;
+ knot_rrset_t *rrset;
+ int errors = 0;
+
+ node *n = NULL;
+ WALK_LIST(n, *rrset_list) {
+ test_rrset_t *test_rrset = (test_rrset_t *)n;
+ rrset = rrset_from_test_rrset(test_rrset);
+ if (rrset == NULL) {
+ diag("Could not create rrset from test data");
+ return 0;
+ }
+
+ /* create node from test_node structure. Always the first one.*/
+ knot_dname_t *owner =
+ dname_from_test_dname(test_rrset->owner);
+ if (owner == NULL) {
+ diag("Could not create owner from test data");
+ return 0;
+ }
+
+ tmp = knot_node_new(owner, NULL, 0);
+
+ if (knot_node_add_rrset(tmp, rrset, 0) != 0) {
+ errors++;
+ diag("Failed to insert rrset into node");
+ }
+
+ /* check if rrset is really there */
+
+ const knot_rrset_t *rrset_from_node = NULL;
+ if ((rrset_from_node =
+ knot_node_rrset(tmp, rrset->type)) == NULL) {
+ errors++;
+ diag("Inserted rrset could not be found");
+ continue;
+ }
+
+ /* compare rrset from node with original rrset */
+
+ const knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+
+ int cmp = 0;
+
+ if ((rrset_from_node->rdata == NULL) &&
+ (rrset->rdata == NULL)) {
+ cmp = 0;
+ } else if ((rrset_from_node->rdata != NULL) &&
+ (rrset->rdata != NULL)) {
+ cmp = knot_rdata_compare(rrset_from_node->rdata,
+ rrset->rdata,
+ desc->wireformat);
+ } else { /* one is not NULL and other is -> error */
+ cmp = 1;
+ }
+
+ if (!((rrset_from_node->type == rrset->type) &&
+ (rrset_from_node->rclass == rrset->rclass) &&
+ (rrset_from_node->ttl == rrset->ttl) &&
+ (rrset_from_node->rrsigs == rrset->rrsigs) &&
+ (cmp == 0))) {
+ errors++;
+ diag("Values in found rrset are wrong");
+ }
+
+ knot_node_free(&tmp, 1, 0);
+ }
+
+ return (errors == 0);
+}
+
+//static int test_node_get_rrset()
+//{
+// knot_node_t *tmp;
+// knot_rrset_t *rrset;
+// int errors = 0;
+
+// knot_node_t *nodes[TEST_NODES];
+
+// for (int i = 0; i < TEST_NODES && !errors; i++) {
+// tmp = knot_node_new(&test_nodes[i].owner,
+// test_nodes[i].parent);
+// nodes[i] = tmp;
+// for (int j = 0; j < RRSETS; j++) {
+// knot_node_add_rrset(tmp, &rrsets[j]);
+// }
+// }
+
+// for (int i = 0; i < TEST_NODES && !errors; i++) {
+// for (int j = 0; j < RRSETS; j++) {
+// rrset = &rrsets[j];
+// if (knot_node_rrset(nodes[i], rrset->type)
+// != rrset) {
+// errors++;
+// diag("Failed to get proper rrset from node");
+// }
+// }
+// knot_node_free(&nodes[i], 0);
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_node_get_parent()
+//{
+// knot_node_t *tmp;
+// knot_rrset_t *rrset;
+// int errors = 0;
+
+// knot_node_t *nodes[TEST_NODES];
+
+// for (int i = 0; i < TEST_NODES && !errors; i++) {
+// tmp = knot_node_new(&test_nodes[i].owner,
+// test_nodes[i].parent);
+// nodes[i] = tmp;
+// rrset = &rrsets[i];
+// knot_node_add_rrset(tmp, rrset);
+// }
+
+// for (int i = 0; i < TEST_NODES && !errors; i++) {
+// rrset = &rrsets[i];
+// if (knot_node_parent(nodes[i]) != test_nodes[i].parent) {
+// errors++;
+// diag("Failed to get proper parent from node");
+// }
+// knot_node_free(&nodes[i], 0);
+// }
+// return (errors == 0);
+//}
+
+//static int test_node_sorting()
+//{
+// knot_node_t *tmp = NULL;
+// knot_rrset_t *rrset = NULL;
+// int errors = 0;
+
+// knot_dname_t *owner = dname_from_test_dname(test_nodes[0].owner);
+
+// tmp = knot_node_new(owner,
+// (knot_node_t *)test_nodes[0].parent);
+
+// /* Will add rrsets to node. */
+// knot_node_add_rrset(tmp, rrset);
+// }
+
+// const skip_node_t *node = skip_first(tmp->rrsets);
+
+// int last = *((uint16_t *)node->key);
+
+// /* TODO there is now an API function knot_node_rrsets ... */
+
+// /* Iterates through skip list and checks, whether it is sorted. */
+
+// while ((node = skip_next(node)) != NULL) {
+// if (last > *((uint16_t *)node->key)) {
+// errors++;
+// diag("RRset sorting error");
+// }
+// last = *((uint16_t *)node->key);
+// }
+
+// knot_node_free(&tmp, 1);
+// return (errors == 0);
+//}
+
+//static int test_node_delete()
+//{
+// int errors = 0;
+
+// knot_node_t *tmp_node;
+
+// for (int i = 0; i < TEST_NODES; i++) {
+// knot_dname_t *owner =
+// dname_from_test_dname(test_nodes[i].owner);
+// tmp_node = knot_node_new(owner,
+// (knot_node_t *)test_nodes[i].parent);
+
+// knot_node_free(&tmp_node, 1);
+
+// errors += (tmp_node != NULL);
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_node_set_parent()
+//{
+// knot_node_t *tmp_parent = (knot_node_t *)0xABCDEF;
+// int errors = 0;
+
+// knot_node_t *tmp_node;
+
+// for (int i = 0; i < TEST_NODES; i++) {
+// tmp_node = knot_node_new(&test_nodes[i].owner,
+// test_nodes[i].parent);
+
+// knot_node_set_parent(tmp_node, tmp_parent);
+
+// if (tmp_node->parent != tmp_node->parent) {
+// diag("Parent node is wrongly set.");
+// errors++;
+// }
+// knot_node_free(&tmp_node, 0);
+// }
+// return (errors == 0);
+//}
+
+//static int test_node_free_rrsets()
+//{
+// int errors = 0;
+
+// knot_node_t *tmp_node;
+
+// for (int i = 0; i < TEST_NODES; i++) {
+// knot_dname_t *owner =
+// dname_from_test_dname(test_nodes[i].owner);
+// if (owner == NULL) {
+// return 0;
+// }
+
+// tmp_node = knot_node_new(owner,
+// (knot_node_t *)test_nodes[i].parent);
+
+// knot_node_free_rrsets(tmp_node, 0);
+
+// errors += (tmp_node->rrsets != NULL);
+
+// knot_node_free(&tmp_node, 1);
+// }
+// return (errors == 0);
+//}
+
+static const int KNOT_NODE_TEST_COUNT = 2;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_node_tests_count(int argc, char *argv[])
+{
+ return KNOT_NODE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_node_tests_run(int argc, char *argv[])
+{
+ test_data_t *data = data_for_knot_tests;
+ int res = 0,
+ res_final = 1;
+
+ res = test_node_create(&data->node_list);
+ ok(res, "node: create");
+ res_final *= res;
+
+
+ ok((res = test_node_add_rrset(&data->rrset_list)), "node: add");
+ res_final *= res;
+
+// ok((res = test_node_get_rrset()), "node: get");
+// res_final *= res;
+
+// ok((res = test_node_get_parent()), "node: get parent");
+// res_final *= res;
+
+// ok((res = test_node_set_parent()), "node: set parent");
+// res_final *= res;
+
+// ok((res = test_node_sorting()), "node: sort");
+// res_final *= res;
+
+// ok((res = test_node_free_rrsets()), "node: free rrsets");
+// res_final *= res;
+
+// endskip;
+
+// ok((res = test_node_delete()), "node: delete");
+// //res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/node_tests_realdata.h b/src/tests/libknot/realdata/libknot/node_tests_realdata.h
new file mode 100644
index 0000000..a90179f
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/node_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_NODE_TESTS_H_
+#define _KNOTD_NODE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api node_tests_api;
+
+#endif /* _KNOTD_NODE_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/packet_tests_realdata.c b/src/tests/libknot/realdata/libknot/packet_tests_realdata.c
new file mode 100644
index 0000000..08c0882
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/packet_tests_realdata.c
@@ -0,0 +1,679 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+
+#include <config.h>
+#include "knot/common.h"
+#include "packet_tests_realdata.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/packet.h"
+#include "libknot/packet/response.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#ifdef TEST_WITH_LDNS
+#include "ldns/ldns.h"
+#endif
+
+static int packet_tests_count(int argc, char *argv[]);
+static int packet_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api packet_tests_api = {
+ "DNS library - packet", //! Unit name
+ &packet_tests_count, //! Count scheduled tests
+ &packet_tests_run //! Run scheduled tests
+};
+
+#ifdef TEST_WITH_LDNS
+/* Compares one rdata knot with rdata from ldns.
+ * Comparison is done through comparing wireformats.
+ * Returns 0 if rdata are the same, 1 otherwise
+ */
+int compare_rr_rdata(knot_rdata_t *rdata, ldns_rr *rr,
+ uint16_t type)
+{
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ for (int i = 0; i < rdata->count; i++) {
+ /* check for ldns "descriptors" as well */
+
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) {
+ if (rdata->items[i].dname->size !=
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) {
+ diag("%s", rdata->items[i].dname->name);
+ diag("%s", ldns_rdf_data(ldns_rr_rdf(rr, i)));
+ diag("%d", ldns_rdf_size(ldns_rr_rdf(rr, i)));
+ diag("%d", rdata->items[i].dname->size);
+ diag("Dname sizes in rdata differ");
+ return 1;
+ }
+ if (compare_wires_simple(rdata->items[i].dname->name,
+ ldns_rdf_data(ldns_rr_rdf(rr, i)),
+ rdata->items[i].dname->size) != 0) {
+ diag("%s", rdata->items[i].dname->name);
+ diag("%s", ldns_rdf_data(ldns_rr_rdf(rr, i)));
+ diag("Dname wires in rdata differ");
+ return 1;
+ }
+ } else {
+ /* Compare sizes first, then actual data */
+ if (rdata->items[i].raw_data[0] !=
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) {
+ /* \note ldns stores the size including the
+ * length, knot does not */
+ diag("Raw data sizes in rdata differ");
+ diag("knot: %d ldns: %d",
+ rdata->items[i].raw_data[0],
+ ldns_rdf_size(ldns_rr_rdf(rr, i)));
+// hex_print((char *)
+// (rdata->items[i].raw_data + 1),
+// rdata->items[i].raw_data[0]);
+// hex_print((char *)ldns_rdf_data(ldns_rr_rdf(rr,
+// i)),
+// ldns_rdf_size(ldns_rr_rdf(rr, i)));
+ if (abs(rdata->items[i].raw_data[0] -
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) != 1) {
+ return 1;
+ }
+ }
+ if (compare_wires_simple((uint8_t *)
+ (rdata->items[i].raw_data + 1),
+ ldns_rdf_data(ldns_rr_rdf(rr, i)),
+ rdata->items[i].raw_data[0]) != 0) {
+// hex_print((char *)
+// (rdata->items[i].raw_data + 1),
+// rdata->items[i].raw_data[0]);
+// hex_print((char *)
+// ldns_rdf_data(ldns_rr_rdf(rr, i)),
+// rdata->items[i].raw_data[0]);
+ diag("Raw data wires in rdata differ in item "
+ "%d", i);
+
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int compare_rrset_w_ldns_rr(const knot_rrset_t *rrset,
+ ldns_rr_list *rr_set, char check_rdata)
+{
+ /* We should have only one rrset from ldns, although it is
+ * represented as rr_list ... */
+
+ int errors = 0;
+
+ ldns_rr *rr = ldns_rr_list_rr(rr_set, 0);
+ assert(rr);
+ assert(rrset);
+
+ /* compare headers */
+
+ if (rrset->owner->size != ldns_rdf_size(ldns_rr_owner(rr))) {
+ char *tmp_dname = knot_dname_to_str(rrset->owner);
+ diag("RRSet owner names differ in length");
+ diag("ldns: %d, knot: %d", ldns_rdf_size(ldns_rr_owner(rr)),
+ rrset->owner->size);
+ diag("%s", tmp_dname);
+ diag("%s", ldns_rdf_data(ldns_rr_owner(rr)));
+ free(tmp_dname);
+ errors++;
+ }
+
+ if (compare_wires_simple(rrset->owner->name,
+ ldns_rdf_data(ldns_rr_owner(rr)),
+ rrset->owner->size) != 0) {
+ diag("RRSet owner wireformats differ");
+ diag("%s \\w %s\n", rrset->owner->name,
+ ldns_rdf_data(ldns_rr_owner(rr)));
+ errors++;
+ }
+
+ if (rrset->type != ldns_rr_get_type(rr)) {
+ diag("RRset types differ");
+ diag("knot type: %d Ldns type: %d", rrset->type,
+ ldns_rr_get_type(rr));
+ errors++;
+ }
+
+ if (rrset->rclass != ldns_rr_get_class(rr)) {
+ diag("RRset classes differ");
+ errors++;
+ }
+
+ if (rrset->ttl != ldns_rr_ttl(rr)) {
+ diag("RRset TTLs differ");
+ diag("knot: %d ldns: %d", rrset->ttl, ldns_rr_ttl(rr));
+ errors++;
+ }
+
+ /* compare rdatas */
+
+ if (rrset->rdata == NULL) {
+ diag("RRSet has no RDATA!");
+ return errors;
+ }
+ knot_rdata_t *tmp_rdata = rrset->rdata;
+
+ int i = 0;
+
+ while ((rr = ldns_rr_list_pop_rr(rr_set))) {
+ assert(rr);
+
+ if (compare_rr_rdata(tmp_rdata, rr, rrset->type) != 0) {
+ diag("Rdata differ");
+ return 1;
+ }
+
+ tmp_rdata = tmp_rdata->next;
+ i++;
+ }
+
+//// if (check_rdata) {
+//// if (compare_rr_rdata(rrset->rdata, rr, rrset->type) != 0) {
+//// diag("Rdata differ");
+//// errors++;
+//// }
+//// }
+
+ return errors;
+}
+
+int compare_rrsets_w_ldns_rrlist(const knot_rrset_t **rrsets,
+ ldns_rr_list *rrlist, int count)
+{
+ int errors = 0;
+
+ /* There are no rrsets currenty. Everything is just rr */
+
+ ldns_rr_list *rr_set = NULL;
+
+ ldns_rr_list_sort(rrlist);
+
+ if (count < 0) {
+ return 0;
+ }
+
+ for (int i = 0; i < count ; i++) {
+ /* normally ldns_pop_rrset or such should be here */
+
+ rr_set = ldns_rr_list_pop_rrset(rrlist);
+ /* Get one rr from list. */
+ ldns_rr *rr = ldns_rr_list_rr(rr_set, 0);
+ assert(rr);
+
+ if (rr_set == NULL) {
+ diag("Ldns and knot structures have different "
+ "counts of rrsets.");
+ diag("knot: %d ldns: %d",
+ count, (count - 1) - i);
+ return -1;
+ }
+
+// diag("RRset from ldns is %d long", ldns_rr_list_rr_count(rr_set));
+
+// diag("Got type from ldns: %d (%d)\n", ldns_rr_get_type(rr), i);
+
+ int j = 0;
+ for (j = 0; j < count; j++) {
+// diag("Got type from knot: %d\n", rrsets[j]->type);
+ if (rrsets[j]->type == ldns_rr_get_type(rr) &&
+ rrsets[j]->owner->size ==
+ ldns_rdf_size(ldns_rr_owner(rr)) &&
+ (compare_wires_simple(ldns_rdf_data(ldns_rr_owner(rr)), rrsets[j]->owner->name,
+ rrsets[j]->owner->size) == 0)) {
+ errors += compare_rrset_w_ldns_rr(rrsets[j],
+ rr_set, 1);
+ break;
+ }
+ }
+ if (j == count) {
+ diag("There was no RRSet of the same type!");
+// errors++;
+ }
+ }
+
+ return errors;
+}
+
+int check_packet_w_ldns_packet(knot_packet_t *packet,
+ ldns_pkt *ldns_packet,
+ int check_header,
+ int check_question,
+ int check_body,
+ int check_edns)
+{
+ int errors = 0;
+ if (check_header) {
+// if (packet->header.id != ldns_pkt_id(ldns_packet)) {
+// diag("response ID does not match - %d %d",
+// packet->header.id,
+// ldns_pkt_id(ldns_packet));
+// errors++;
+// }
+
+ /* qdcount is always 1 in knot's case */
+
+ /* TODO check flags1 and flags2 - no API for that,
+ * write my own */
+
+ if (packet->header.ancount !=
+ ldns_pkt_ancount(ldns_packet)) {
+ diag("Answer RRSet count wrongly converted");
+ errors++;
+ }
+
+ if (packet->header.nscount !=
+ ldns_pkt_nscount(ldns_packet)) {
+ diag("Authority RRSet count wrongly converted.\n"
+ "got %d should be %d",
+ packet->header.nscount,
+ ldns_pkt_nscount(ldns_packet));
+ errors++;
+ }
+
+ /* - 1 because ldns does not include OPT_RR to additional "
+ "section */
+ int minus = (!ldns_pkt_edns_version(ldns_packet)) ? 1 : 0;
+// int minus = 0;
+
+ if ((packet->header.arcount - minus) !=
+ ldns_pkt_arcount(ldns_packet)) {
+ diag("Additional RRSet count wrongly converted.\n"
+ "got %d should be %d",
+ packet->header.arcount,
+ ldns_pkt_arcount(ldns_packet));
+ errors++;
+ }
+
+ /*!< \todo Check OPT RR! */
+
+ if (errors) {
+ return errors;
+ }
+ }
+ /* Header checked */
+
+ /* Question section */
+
+ int ret = 0;
+ if (check_question) {
+ knot_rrset_t *question_rrset =
+ knot_rrset_new(packet->
+ question.qname,
+ packet->
+ question.qtype,
+ packet->
+ question.qclass,
+ 3600);
+
+ if ((ret = compare_rrset_w_ldns_rr(question_rrset,
+ ldns_pkt_question(ldns_packet), 0)) != 0) {
+ diag("Question rrsets wrongly converted");
+ errors++;
+ }
+ knot_rrset_free(&question_rrset);
+ }
+
+ if (check_body) {
+
+ /* other RRSets */
+
+ if ((ret =
+ compare_rrsets_w_ldns_rrlist(packet->answer,
+ ldns_pkt_answer(ldns_packet),
+ knot_packet_answer_rrset_count(packet))) != 0) {
+ diag("Answer rrsets wrongly converted");
+ errors++;
+ }
+
+
+
+ if ((ret = compare_rrsets_w_ldns_rrlist(packet->authority,
+ ldns_pkt_authority(ldns_packet),
+ knot_packet_authority_rrset_count(packet))) != 0) {
+ diag("Authority rrsets wrongly converted - %d", ret);
+ errors++;
+ }
+
+ /* We don't want to test OPT RR, which is the last rrset
+ * in the additional section */
+
+ if ((ret = compare_rrsets_w_ldns_rrlist(packet->additional,
+ ldns_pkt_additional(ldns_packet),
+ knot_packet_additional_rrset_count(packet) - 1)) != 0) {
+ diag("Additional rrsets wrongly converted");
+ errors++;
+ }
+
+ }
+
+ if (check_edns) {
+
+ /* OPT RR */
+
+ if (ldns_pkt_edns(ldns_packet)) {
+ /* if (packet->edns_packet == NULL) {
+ diag("ldns has edns section, knot has not");
+ return 1;
+ } */
+
+ knot_opt_rr_t *opt = &(packet->opt_rr);
+
+ if (ldns_pkt_edns_udp_size(ldns_packet) !=
+ knot_edns_get_payload(opt)) {
+ diag("Payloads in EDNS are different");
+ errors++;
+ }
+
+ if (ldns_pkt_edns_version(ldns_packet) !=
+ knot_edns_get_version(opt)) {
+ diag("Versions in EDNS are different");
+ errors++;
+ }
+
+ if (ldns_pkt_edns_extended_rcode(ldns_packet) !=
+ knot_edns_get_ext_rcode(opt)) {
+ diag("Extended rcodes in EDNS are different");
+ errors++;
+ }
+
+ /* TODO parse flags do bit, z value ... */
+ }
+ }
+
+ return errors;
+}
+#endif
+
+extern knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset);
+extern knot_dname_t *dname_from_test_dname(const test_dname_t *test_dname);
+
+/* Converts knot_rrset_t to knot_opt_rr */
+static knot_opt_rr_t *opt_rrset_to_opt_rr(knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ knot_opt_rr_t *opt_rr = knot_edns_new();
+ assert(opt_rr);
+
+ knot_edns_set_payload(opt_rr, rrset->rclass);
+
+ knot_edns_set_ext_rcode(opt_rr, rrset->ttl);
+
+ /* TODO rdata? mostly empty, I guess, but should be done */
+
+ return opt_rr;
+}
+
+knot_packet_t *packet_from_test_response(test_response_t *test_packet)
+{
+ knot_rrset_t *parsed_opt = NULL;
+
+ for (int j = 0; j < test_packet->arcount; j++) {
+ if (test_packet->additional[j]->type ==
+ KNOT_RRTYPE_OPT) {
+ parsed_opt =
+ rrset_from_test_rrset(
+ test_packet->additional[j]);
+ assert(parsed_opt);
+ break;
+ }
+ }
+
+ knot_opt_rr_t *opt_rr = NULL;
+ if (parsed_opt != NULL) {
+ opt_rr =
+ opt_rrset_to_opt_rr(parsed_opt);
+ assert(opt_rr);
+ } else {
+ opt_rr = NULL;
+ }
+
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+ knot_packet_set_max_size(packet, 1024 * 10);
+
+ if (opt_rr != NULL) {
+ packet->opt_rr = *opt_rr;
+ }
+
+ packet->header.id = test_packet->id;
+ packet->header.qdcount = test_packet->qdcount;
+
+ packet->question.qname = dname_from_test_dname(test_packet->qname);
+ packet->size += test_packet->qname->size;
+ packet->question.qtype = test_packet->qtype;
+ packet->question.qclass = test_packet->qclass;
+
+ packet->size += 4;
+
+ packet->answer =
+ malloc(sizeof(knot_rrset_t *) * test_packet->ancount);
+ assert(packet->answer);
+
+ for (int j = 0; j < test_packet->ancount; j++) {
+ if (&(test_packet->answer[j])) {
+ packet->answer[packet->an_rrsets++] =
+ rrset_from_test_rrset(test_packet->answer[j]);
+ }
+ }
+
+ packet->authority =
+ malloc(sizeof(knot_rrset_t *) * test_packet->nscount);
+ assert(packet->answer);
+
+ for (int j = 0; j < test_packet->nscount; j++) {
+ if (&(test_packet->authority[j])) {
+ packet->authority[packet->ns_rrsets++] =
+ rrset_from_test_rrset(test_packet->authority[j]);
+ }
+ }
+
+ packet->authority =
+ malloc(sizeof(knot_rrset_t *) * test_packet->arcount);
+ assert(packet->answer);
+
+ for (int j = 0; j < test_packet->arcount; j++) {
+ if (&(test_packet->additional[j])) {
+ if (test_packet->additional[j]->type ==
+ KNOT_RRTYPE_OPT) {
+ continue;
+ }
+ packet->additional[packet->ar_rrsets++] =
+ rrset_from_test_rrset(test_packet->additional[j]);
+ }
+ }
+
+ return packet;
+}
+
+static int test_packet_parse_from_wire(list raw_response_list)
+{
+#ifdef TEST_WITH_LDNS
+ int errors = 0;
+
+ node *n = NULL;
+ WALK_LIST(n ,raw_response_list) {
+ test_raw_packet_t *raw_packet = (test_raw_packet_t *)n;
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ int ret = 0;
+ if ((ret =
+ knot_packet_parse_from_wire(packet, raw_packet->data,
+ raw_packet->size, 0)) !=
+ KNOT_EOK) {
+ diag("Warning: could not parse wire! "
+ "(might be caused by malformed dump) - "
+ "knot error: %s", knot_strerror(ret));
+// hex_print(raw_packet->data,
+// raw_packet->size);
+ continue;
+ }
+
+ ldns_pkt *ldns_packet = NULL;
+
+ if (ldns_wire2pkt(&ldns_packet, raw_packet->data,
+ raw_packet->size) != LDNS_STATUS_OK) {
+ diag("Could not parse wire using ldns");
+ diag("%s",
+ ldns_get_errorstr_by_id(ldns_wire2pkt(&ldns_packet,
+ raw_packet->data,
+ raw_packet->size)));
+ return 0;
+ }
+
+ if (check_packet_w_ldns_packet(packet, ldns_packet, 1,
+ 1, 1, 1) != 0) {
+ diag("Wrongly created packet");
+ errors++;
+ }
+
+ ldns_pkt_free(ldns_packet);
+ knot_packet_free(&packet);
+ }
+
+ return (errors == 0);
+#endif
+#ifndef TEST_WITH_LDNS
+ diag("Enable ldns to test this feature");
+ return 0;
+#endif
+}
+
+static int test_packet_to_wire(list raw_response_list)
+{
+#ifdef TEST_WITH_LDNS
+ int errors = 0;
+ /*!< \todo test queries too! */
+// /* We'll need data from both lists. */
+// test_packet_t **test_packets = NULL;
+// uint test_packet_count = 0;
+// node *n = NULL;
+// WALK_LIST(n, response_list) {
+// test_packet_count++;
+// }
+
+// test_packets =
+// malloc(sizeof(test_packet_t *) * test_packet_count);
+// assert(test_packets);
+// int i = 0;
+// WALK_LIST(n, response_list) {
+// test_packets[i++] = (test_response_t *)n;
+// }
+
+// test_raw_packet_t **test_packets = NULL;
+// uint test_packet_count = 0;
+// n = NULL;
+// WALK_LIST(n, raw_response_list) {
+// test_packet_count++;
+// }
+
+// test_packets =
+// malloc(sizeof(test_raw_packet_t *) * test_packet_count);
+// assert(test_packets);
+// i = 0;
+// WALK_LIST(n, raw_response_list) {
+// test_packets[i++] = (test_raw_packet_t *)n;
+// }
+
+// assert(test_response_count == test_packet_count);
+ node *n = NULL;
+ WALK_LIST(n, raw_response_list) {
+ /* Create packet from raw response. */
+ knot_packet_t *packet =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(packet);
+ test_raw_packet_t *raw_packet = (test_raw_packet_t *)n;
+ if (knot_packet_parse_from_wire(packet, raw_packet->data,
+ raw_packet->size, 0) !=
+ KNOT_EOK) {
+ diag("Warning: could not parse wire! "
+ "(might be caused be malformed dump)");
+ continue;
+ }
+ knot_packet_set_max_size(packet, 1024 * 10);
+ /* Use this packet to create wire */
+ uint8_t *wire = NULL;
+ size_t size = 0;
+ if (knot_packet_to_wire(packet, &wire ,&size) != KNOT_EOK) {
+ diag("Could not convert packet to wire");
+ }
+ /* Create ldns packet from created wire */
+ ldns_pkt *ldns_packet = NULL;
+
+ if (ldns_wire2pkt(&ldns_packet, wire,
+ size) != LDNS_STATUS_OK) {
+ diag("Could not parse wire using ldns");
+ /*!< \todo get rid of this */
+ diag("%s",
+ ldns_get_errorstr_by_id(ldns_wire2pkt(&ldns_packet,
+ wire,
+ size)));
+ return 0;
+ }
+
+ if (check_packet_w_ldns_packet(packet, ldns_packet, 1, 1, 1,
+ 1) != 0) {
+ diag("Packet wrongly converted to wire!");
+ errors++;
+ }
+ knot_packet_free(&packet);
+ ldns_pkt_free(ldns_packet);
+ }
+
+ return (errors == 0);
+#endif
+#ifndef TEST_WITH_LDNS
+ diag("Enable ldns to test this feature!");
+ return 0;
+#endif
+}
+
+static const uint KNOT_PACKET_TEST_COUNT = 2;
+
+static int packet_tests_count(int argc, char *argv[])
+{
+ return KNOT_PACKET_TEST_COUNT;
+}
+
+static int packet_tests_run(int argc, char *argv[])
+{
+ const test_data_t *data = data_for_knot_tests;
+
+ int res = 0;
+ todo();
+ ok(res = test_packet_parse_from_wire(data->raw_packet_list),
+ "packet: from wire");
+ diag("Resolve issue with arcount.");
+ endtodo;
+// skip(!res, 1);
+ ok(test_packet_to_wire(data->raw_packet_list), "packet: to wire");
+// endskip;
+
+ return 1;
+}
+
diff --git a/src/tests/libknot/realdata/libknot/packet_tests_realdata.h b/src/tests/libknot/realdata/libknot/packet_tests_realdata.h
new file mode 100644
index 0000000..c0e0479
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/packet_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_PACKET_REALDATA_TESTS_H_
+#define _KNOTD_PACKET_REALDATA_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api packet_tests_api;
+
+#endif /* _KNOTD_PACKET_REALDATA_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c
new file mode 100644
index 0000000..f4ba64c
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c
@@ -0,0 +1,329 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "tests/libknot/realdata/libknot/rdata_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/common.h"
+#include "libknot/rdata.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/util/utils.h"
+#include "libknot/util/error.h"
+
+static int knot_rdata_tests_count(int argc, char *argv[]);
+static int knot_rdata_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api rdata_tests_api = {
+ "DNS library - rdata", //! Unit name
+ &knot_rdata_tests_count, //! Count scheduled tests
+ &knot_rdata_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+extern int check_domain_name(const knot_dname_t *dname,
+ const test_dname_t *test_dname);
+
+extern int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count);
+
+/*!
+ * \brief Checks if all RDATA items in the given RDATA structure are correct.
+ *
+ * \return Number of errors encountered. Error is either if some RDATA item
+ * is not set (i.e. NULL) or if it has other than the expected value.
+ */
+static int check_rdata(const knot_rdata_t *rdata,
+ const test_rdata_t *test_rdata)
+{
+ assert(rdata != NULL);
+ assert(test_rdata != NULL);
+
+ int errors = 0;
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(test_rdata->type);
+ //note("check_rdata(), RRType: %u", rrtype);
+
+ for (int i = 0; i < desc->length; ++i) {
+
+ switch (desc->wireformat[i]) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ if (check_domain_name(rdata->items[i].dname,
+ test_rdata->items[i].dname) != 0) {
+ errors++;
+ diag("Rdata contains wrong dname item");
+ }
+ break;
+ default:
+ if (test_rdata->items[i].raw_data[0] !=
+ rdata->items[i].raw_data[0]) {
+ diag("Raw rdata in items have different "
+ "sizes!");
+ return 0;
+ }
+
+ errors +=
+ compare_wires_simple(
+ (uint8_t *)test_rdata->items[i].raw_data,
+ (uint8_t *)rdata->items[i].raw_data,
+ (uint)rdata->items[i].raw_data[0]);
+ }
+ }
+ return errors;
+}
+
+extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname);
+
+///*!
+// * \brief Tests knot_rdata_set_item().
+// *
+// * \retval > 0 on success.
+// * \retval 0 otherwise.
+// */
+//static int test_rdata_set_item(list rdata_list)
+//{
+// node *n = NULL;
+// WALK_LIST(n, rdata_list) {
+// knot_rdata_t *rdata = knot_rdata_new();
+// assert(rdata);
+// test_rdata_t *test_rdata = (test_rdata_t *)n;
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(test_rdata->type);
+// for (int i = 0; i < test_rdata->count; i++) {
+// knot_rdata_item_t item;
+// if (test_rdata->items[i].type == TEST_ITEM_DNAME) {
+// item.dname =
+// dname_from_test_dname(
+// test_rdata->items[i].dname);
+// } else {
+// item.raw_data = test_rdata->items[i].raw_data;
+// }
+// if (knot_rdata_set_item(rdata, i, item) != 0) {
+// diag("Could not set item, rdata count: %d",
+// rdata->count);
+// return 0;
+// }
+// }
+
+// /* Check that all items are OK */
+// if (check_rdata(rdata, test_rdata) != 0) {
+// return 0;
+// }
+// }
+// return 1;
+//}
+
+static knot_rdata_item_t *items_from_test_items(test_item_t *test_items,
+ size_t count)
+{
+ knot_rdata_item_t *items =
+ malloc(sizeof(knot_rdata_item_t) * count);
+ assert(items);
+ for (int i = 0; i < count; i++) {
+ if (test_items[i].type == TEST_ITEM_DNAME) {
+ items[i].dname =
+ dname_from_test_dname(test_items[i].dname);
+ } else {
+ items[i].raw_data = test_items[i].raw_data;
+ }
+ }
+
+ return items;
+}
+
+static int test_rdata_set_items(list rdata_list)
+{
+ int errors = 0;
+
+ // check error return values
+ knot_rdata_t *rdata = knot_rdata_new();
+ assert(rdata);
+
+ node *n = NULL;
+ WALK_LIST(n, rdata_list) {
+ test_rdata_t *test_rdata = (test_rdata_t *)n;
+ knot_rdata_t *rdata = knot_rdata_new();
+
+ /* create dnslib items from tests items. */
+ knot_rdata_item_t *items =
+ items_from_test_items(test_rdata->items,
+ test_rdata->count);
+
+ assert(items);
+ assert(test_rdata->count > 0);
+ assert(rdata->items == NULL);
+
+ if (knot_rdata_set_items(rdata, items,
+ test_rdata->count) != 0) {
+ diag("Could not set items!");
+ errors++;
+ }
+
+ if (check_rdata(rdata, test_rdata) != 0) {
+ diag("Wrong rdata after knot_rdata_set_items!");
+ errors++;
+ }
+
+ knot_rdata_free(&rdata);
+ }
+
+ return (errors == 0);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tests knot_rdata_get_item().
+ *
+ * \retval > 0 on success.
+ * \retval 0 otherwise.
+ */
+static int test_rdata_get_item(list rdata_list)
+{
+ node *n = NULL;
+ WALK_LIST(n, rdata_list) {
+ test_rdata_t *test_rdata = (test_rdata_t *)n;
+ knot_rdata_t *rdata = knot_rdata_new();
+ assert(rdata);
+ knot_rdata_item_t *items =
+ items_from_test_items(test_rdata->items,
+ test_rdata->count);
+ assert(knot_rdata_set_items(rdata, items,
+ test_rdata->count) == 0);
+ knot_rdata_item_t *new_items =
+ malloc(sizeof(knot_rdata_item_t) * test_rdata->count);
+ for (int i = 0; i < test_rdata->count; i++) {
+ knot_rdata_item_t *item =
+ knot_rdata_get_item(rdata, i);
+ if (item == NULL) {
+ diag("Could not get item");
+ return 0;
+ }
+ new_items[i] = *item;
+ }
+
+ knot_rdata_free(&rdata);
+ free(items);
+
+ knot_rdata_t *new_rdata = knot_rdata_new();
+ assert(new_rdata);
+ assert(knot_rdata_set_items(new_rdata,
+ new_items,
+ test_rdata->count) == 0);
+
+ if (check_rdata(new_rdata, test_rdata) != 0) {
+ diag("Wrong rdata created using rdata_get_item");
+ return 0;
+ }
+
+ knot_rdata_free(&new_rdata);
+ free(new_items);
+ }
+
+ return 1;
+}
+
+//static int test_rdata_wire_size()
+//{
+// knot_rdata_t *rdata;
+// int errors = 0;
+
+// // generate some random data
+// uint8_t data[KNOT_MAX_RDATA_WIRE_SIZE];
+// generate_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE);
+
+// for (int i = 0; i <= KNOT_RRTYPE_LAST; ++i) {
+// rdata = knot_rdata_new();
+
+// int size =
+// fill_rdata(data, KNOT_MAX_RDATA_WIRE_SIZE, i, rdata);
+
+// if (size < 0) {
+// ++errors;
+// } else {
+// int counted_size = knot_rdata_wire_size(rdata,
+// knot_rrtype_descriptor_by_type(i)->wireformat);
+// if (size != counted_size) {
+// diag("Wrong wire size computed (type %d):"
+// " %d (should be %d)",
+// i, counted_size, size);
+// ++errors;
+// }
+// }
+
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(i);
+
+// for (int x = 0; x < desc->length; x++) {
+// if (desc->wireformat[x] ==
+// KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_COMPRESSED_DNAME ||
+// desc->wireformat[x] ==
+// KNOT_RDATA_WF_LITERAL_DNAME) {
+// knot_dname_free(&(rdata->items[x].dname));
+// }
+// }
+// knot_rdata_free(&rdata);
+// }
+
+// return (errors == 0);
+//}
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+
+static const int KNOT_RDATA_TEST_COUNT = 2;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_rdata_tests_count(int argc, char *argv[])
+{
+ return KNOT_RDATA_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_rdata_tests_run(int argc, char *argv[])
+{
+ test_data_t *data = data_for_knot_tests;
+ int res = 0,
+ res_final = 1;
+
+ ok(res = test_rdata_set_items(data->rdata_list),
+ "rdata: set items all at once");
+ res_final *= res;
+
+ ok(res = test_rdata_get_item(data->rdata_list),
+ "rdata: get item");
+ res_final *= res;
+
+// ok(res = test_rdata_set_item(data->rdata_list),
+// "rdata: set items one-by-one");
+// res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h
new file mode 100644
index 0000000..570b2b1
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h
@@ -0,0 +1,53 @@
+/*!
+ * \file rdata_tests.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ *
+ * Contains unit tests for RDATA (knot_rdata_t) and RDATA item
+ * (knot_rdata_item_t) structures.
+ *
+ * Contains tests for:
+ * - creating empty RDATA structure with or without reserved space.
+ * - setting RDATA items one-by-one
+ * - setting RDATA items all at once
+ *
+ * As for now, the tests use several (TEST_RDATAS) RDATA structures, each
+ * with different number of RDATA items (given by test_rdatas). These are all
+ * initialized to pointers derived from RDATA_ITEM_PTR (first is RDATA_ITEM_PTR,
+ * second RDATA_ITEM_PTR + 1, etc.). The functions only test if the pointer
+ * is set properly.
+ *
+ * \todo It may be better to test also some RDATAs with predefined contents,
+ * such as some numbers, some domain name, etc. For this purpose, we'd
+ * need RDATA descriptors (telling the types of each RDATA item within an
+ * RDATA).
+ *
+ * \todo It will be fine to test all possible output values of all functions,
+ * e.g. test whether knot_rdata_get_item() returns NULL when passed an
+ * illegal position, etc.
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_RDATA_TESTS_H_
+#define _KNOTD_RDATA_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api rdata_tests_api;
+
+#endif /* _KNOTD_RDATA_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/response_tests_realdata.c b/src/tests/libknot/realdata/libknot/response_tests_realdata.c
new file mode 100644
index 0000000..5bbda36
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/response_tests_realdata.c
@@ -0,0 +1,173 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/* blame: jan.kadlec@nic.cz */
+
+#include <assert.h>
+
+#include "packet_tests_realdata.h"
+#include "knot/common.h"
+#include "libknot/util/error.h"
+#include "libknot/packet/packet.h"
+#include "libknot/packet/response.h"
+/* *test_t structures */
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#ifdef TEST_WITH_LDNS
+#include "ldns/packet.h"
+#endif
+
+static int response_tests_count(int argc, char *argv[]);
+static int response_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api response_tests_api = {
+ "DNS library - response", //! Unit name
+ &response_tests_count, //! Count scheduled tests
+ &response_tests_run //! Run scheduled tests
+};
+
+#ifdef TEST_WITH_LDNS
+extern int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count);
+extern int compare_rr_rdata(knot_rdata_t *rdata, ldns_rr *rr, uint16_t type);
+extern int compare_rrset_w_ldns_rr(const knot_rrset_t *rrset,
+ ldns_rr *rr, char check_rdata);
+extern int compare_rrsets_w_ldns_rrlist(const knot_rrset_t **rrsets,
+ ldns_rr_list *rrlist, int count);
+
+extern int check_packet_w_ldns_packet(knot_packet_t *packet,
+ ldns_pkt *ldns_packet,
+ int check_header,
+ int check_question,
+ int check_body,
+ int check_edns);
+#endif
+
+extern knot_packet_t *packet_from_test_response(test_response_t *response);
+
+static int test_response_init_from_query(list query_list)
+{
+ int errors = 0;
+ node *n = NULL;
+ WALK_LIST(n, query_list) {
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ knot_packet_t *query =
+ packet_from_test_response((test_response_t *)n);
+ assert(query);
+ knot_packet_set_max_size(response, 1024 * 10);
+ if (knot_response_init_from_query(response,
+ query) != KNOT_EOK) {
+ diag("Could not init response from query!");
+ errors++;
+ }
+ knot_packet_free(&response);
+ knot_packet_free(&query);
+ }
+ return (errors == 0);
+}
+
+//static int test_response_add_opt(list opt_list)
+//{
+// int errors = 0;
+// node *n = NULL;
+// WALK_LIST(n, query_list) {
+// knot_packet_t *response =
+// knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+// assert(response);
+// knot_opt_rr_t *opt =
+// opt_from_test_opt((test_opt_t *)n);
+// assert(query);
+// if (knot_response_add_opt(response,
+// opt, 1)!= KNOT_EOK) {
+// diag("Could not add OPT RR to response!");
+// errors++;
+// }
+// knot_packet_free(&response);
+// knot_opt_rr_free(&opt);
+// }
+// return (errors == 0);
+//}
+
+extern knot_rrset_t *rrset_from_test_rrset(test_rrset_t *test_rrset);
+
+static int test_response_add_generic(int (*func)(knot_packet_t *,
+ const knot_rrset_t *,
+ int, int, int),
+ list rrset_list)
+{
+ /*!< \todo Now adding only one RRSet at the time, try more, use nodes */
+ int errors = 0;
+ node *n = NULL;
+ WALK_LIST(n, rrset_list) {
+ knot_packet_t *response =
+ knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE);
+ assert(response);
+ knot_packet_set_max_size(response,
+ KNOT_PACKET_PREALLOC_RESPONSE * 100);
+ assert(knot_response_init(response) == KNOT_EOK);
+
+ knot_rrset_t *rrset =
+ rrset_from_test_rrset((test_rrset_t *)n);
+ assert(rrset);
+
+ int ret = 0;
+ if ((ret = func(response, rrset, 0, 1, 0)) != KNOT_EOK) {
+ diag("Could not add RRSet to response! Returned: %d",
+ ret);
+ diag("(owner: %s type %s)",
+ ((test_rrset_t *)n)->owner->str,
+ knot_rrtype_to_string((
+ (test_rrset_t *)n)->type));
+ errors++;
+ }
+ knot_packet_free(&response);
+ knot_rrset_deep_free(&rrset, 1, 1, 1);
+ }
+
+ return (errors == 0);
+}
+
+static void test_response_add_rrset(list rrset_list)
+{
+ ok(test_response_add_generic(knot_response_add_rrset_answer,
+ rrset_list),
+ "response: add answer rrset");
+ ok(test_response_add_generic(knot_response_add_rrset_authority,
+ rrset_list),
+ "response: add authority rrset");
+ ok(test_response_add_generic(knot_response_add_rrset_additional,
+ rrset_list),
+ "response: add additional rrset");
+}
+
+static const uint KNOT_response_TEST_COUNT = 4;
+
+static int response_tests_count(int argc, char *argv[])
+{
+ return KNOT_response_TEST_COUNT;
+}
+
+static int response_tests_run(int argc, char *argv[])
+{
+ const test_data_t *data = data_for_knot_tests;
+
+// int res = 0;
+ ok(test_response_init_from_query(data->query_list),
+ "response: init from query");
+ test_response_add_rrset(data->rrset_list);
+ return 1;
+}
diff --git a/src/tests/libknot/realdata/libknot/response_tests_realdata.h b/src/tests/libknot/realdata/libknot/response_tests_realdata.h
new file mode 100644
index 0000000..731604b
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/response_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_PACKET_response_TESTS_H_
+#define _KNOTD_PACKET_response_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api response_tests_api;
+
+#endif /* _KNOTD_PACKET_response_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c
new file mode 100644
index 0000000..cb59f4c
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c
@@ -0,0 +1,289 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "tests/libknot/realdata/libknot/rrset_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/common.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/rrset.h"
+#include "libknot/dname.h"
+#include "libknot/rdata.h"
+#include "libknot/util/utils.h"
+#include "libknot/zone/node.h"
+#include "libknot/util/debug.h"
+
+static int knot_rrset_tests_count(int argc, char *argv[]);
+static int knot_rrset_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api rrset_tests_api = {
+ "DNS library - rrset", //! Unit name
+ &knot_rrset_tests_count, //! Count scheduled tests
+ &knot_rrset_tests_run //! Run scheduled tests
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Unit implementation.
+ */
+
+/* count1 == count2 */
+int compare_wires_simple(uint8_t *wire1, uint8_t *wire2, uint count)
+{
+ int i = 0;
+ while (i < count &&
+ wire1[i] == wire2[i]) {
+ i++;
+ }
+ return (!(count == i));
+}
+
+
+knot_rrset_t *rrset_from_test_rrset(const test_rrset_t *test_rrset)
+{
+// diag("owner: %s\n", test_rrset->owner->str);
+ knot_dname_t *owner =
+ knot_dname_new_from_wire(test_rrset->owner->wire,
+ test_rrset->owner->size, NULL);
+
+// diag("Created owner: %s (%p) from %p\n", knot_dname_to_str(owner),
+// owner, test_rrset->owner);
+
+ if (!owner) {
+ return NULL;
+ }
+
+ knot_rrset_t *ret = knot_rrset_new(owner, test_rrset->type,
+ test_rrset->rclass,
+ test_rrset->ttl);
+
+ /* Add rdata to rrset. */
+ knot_rdata_t *rdata = knot_rdata_new();
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(test_rrset->type);
+
+ node *n = NULL;
+ WALK_LIST(n, test_rrset->rdata_list) {
+ test_rdata_t *test_rdata = (test_rdata_t *)n;
+ if (test_rdata->count != desc->length) {
+ diag("Malformed RRSet data!");
+ knot_rdata_free(&rdata);
+ return ret;
+ }
+ assert(test_rdata->type == test_rrset->type);
+ /* Add items to the actual rdata. */
+ rdata->items = malloc(sizeof(knot_rdata_item_t) * desc->length);
+ if (rdata->items == NULL) {
+ return NULL;
+ }
+// diag("Rdata type: %s\n", knot_rrtype_to_string(test_rrset->type));
+ for (int i = 0; i < desc->length; i++) {
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) {
+// diag("%p\n", test_rdata->items[i].raw_data);
+ assert(test_rdata->items[i].type == TEST_ITEM_DNAME);
+ rdata->items[i].dname =
+ knot_dname_new_from_wire(test_rdata->items[i].dname->wire,
+ test_rdata->items[i].dname->size,
+ NULL);
+ } else {
+// diag("%p\n", test_rdata->items[i].dname);
+ assert(test_rdata->items[i].type == TEST_ITEM_RAW_DATA);
+ assert(test_rdata->items[i].raw_data != NULL);
+ rdata->items[i].raw_data = test_rdata->items[i].raw_data;
+ }
+ }
+ }
+
+ rdata->next = rdata;
+
+ ret->rdata = rdata;
+
+ return ret;
+}
+
+extern int check_domain_name(knot_dname_t *dname, test_dname_t *test_dname);
+
+int check_rrset(const knot_rrset_t *rrset,
+ const test_rrset_t *test_rrset,
+ int check_rdata, int check_items,
+ int check_rrsigs)
+{
+ /* following implementation should be self-explanatory */
+ int errors = 0;
+
+ if (rrset == NULL) {
+ diag("RRSet not created!");
+ return 1;
+ }
+
+ errors += check_domain_name(rrset->owner, test_rrset->owner);
+
+ if (rrset->type != test_rrset->type) {
+ diag("TYPE wrong: %u (should be: %u)", rrset->type,
+ test_rrset->type);
+ ++errors;
+ }
+
+ if (rrset->rclass != test_rrset->rclass) {
+ diag("CLASS wrong: %u (should be: %u)", rrset->rclass,
+ test_rrset->rclass);
+ ++errors;
+ }
+
+ if (rrset->ttl != test_rrset->ttl) {
+ diag("TTL wrong: %u (should be: %u)", rrset->ttl,
+ test_rrset->ttl);
+ ++errors;
+ }
+
+ if (check_rdata) {
+ /* TODO use rdata_compare */
+ knot_rdata_t *rdata = rrset->rdata;
+
+ if (rdata == NULL) {
+ diag("There are no RDATAs in the RRSet");
+ ++errors;
+ }
+
+ if (rdata != NULL) {
+ while (rdata->next != NULL &&
+ rdata->next != rrset->rdata) {
+ rdata = rdata->next;
+ }
+ if (rdata->next == NULL) {
+ diag("The list of RDATAs is not cyclic!");
+ ++errors;
+ } else {
+ assert(rdata->next == rrset->rdata);
+ }
+ }
+ }
+
+ /* Iterate rrset rdata list and compare items. */
+ if (check_items && rrset->rdata != NULL) {
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(rrset->type);
+ node *n = NULL;
+ knot_rdata_t *tmp_rdata = rrset->rdata;
+ WALK_LIST(n, test_rrset->rdata_list) {
+ test_rdata_t *test_rdata = (test_rdata_t *)n;
+ for (int i = 0; i < desc->length; i++) {
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME) {
+ errors += check_domain_name(tmp_rdata->items[i].dname,
+ test_rdata->items[i].dname);
+ } else {
+ assert(tmp_rdata != NULL);
+ errors += compare_wires_simple((uint8_t *)tmp_rdata->items[i].raw_data,
+ (uint8_t *)test_rdata->items[i].raw_data,
+ test_rdata->items[i].raw_data[0]);
+ }
+ }
+ }
+ } else if (check_items && rrset->rdata == NULL) {
+ diag("Could not test items, since rdata is empty!");
+ }
+
+ if (check_rrsigs) {
+ /* there are currently no rrsigs */
+ }
+ return errors;
+}
+
+extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname);
+
+static int test_rrset_create(const list rrset_list)
+{
+ int errors = 0;
+
+ /* Test with real data. */
+ node *n = NULL;
+ WALK_LIST(n, rrset_list) {
+ test_rrset_t *test_rrset = (test_rrset_t *)n;
+ knot_rrset_t *rrset =
+ knot_rrset_new(dname_from_test_dname
+ (test_rrset->owner),
+ test_rrset->type,
+ test_rrset->rclass,
+ test_rrset->ttl);
+ assert(rrset);
+ errors += check_rrset(rrset, test_rrset, 0, 0, 0);
+ knot_rrset_deep_free(&rrset, 1, 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+static int test_rrset_add_rdata(list rrset_list)
+{
+ int errors = 0;
+ node *n = NULL;
+ WALK_LIST(n, rrset_list) {
+ test_rrset_t *test_rrset = (test_rrset_t *)n;
+ knot_rrset_t *tmp_rrset = rrset_from_test_rrset(test_rrset);
+ /* TODO use all the rdata */
+ assert(tmp_rrset->rdata->next = tmp_rrset->rdata);
+ knot_rrset_t *rrset =
+ knot_rrset_new(dname_from_test_dname
+ (test_rrset->owner),
+ test_rrset->type,
+ test_rrset->rclass,
+ test_rrset->ttl);
+ assert(rrset);
+ knot_rrset_add_rdata(rrset, tmp_rrset->rdata);
+ errors += check_rrset(rrset, test_rrset, 1, 1, 1);
+ knot_rrset_free(&tmp_rrset);
+ knot_rrset_deep_free(&rrset, 1, 1, 0);
+
+ }
+ return (errors == 0);
+}
+
+static const int KNOT_RRSET_TEST_COUNT = 2;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_rrset_tests_count(int argc, char *argv[])
+{
+ return KNOT_RRSET_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_rrset_tests_run(int argc, char *argv[])
+{
+ test_data_t *data = data_for_knot_tests;
+
+ int res = 0,
+ res_final = 1;
+
+ res = test_rrset_create(data->rrset_list);
+ ok(res, "rrset: create");
+ res_final *= res;
+
+ ok(res = test_rrset_add_rdata(data->rrset_list), "rrset: add_rdata");
+ res_final *= res;
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h
new file mode 100644
index 0000000..cc3b705
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h
@@ -0,0 +1,35 @@
+/*!
+ * \file rrset_tests.h
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * Contains unit tests for RRSet (knot_rrset_t) and its API.
+ *
+ * Contains tests for:
+ * -
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_RRSET_TESTS_H_
+#define _KNOTD_RRSET_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api rrset_tests_api;
+
+#endif /* _KNOTD_RRSET_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/zone_tests_realdata.c b/src/tests/libknot/realdata/libknot/zone_tests_realdata.c
new file mode 100644
index 0000000..445997f
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/zone_tests_realdata.c
@@ -0,0 +1,335 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "tests/libknot/realdata/libknot/zone_tests_realdata.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/common.h"
+#include "libknot/zone/zone.h"
+#include "libknot/util/error.h"
+#include "libknot/zone/node.h"
+
+static int knot_zone_tests_count(int argc, char *argv[]);
+static int knot_zone_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zone_tests_api = {
+ "DNS library - zone", //! Unit name
+ &knot_zone_tests_count, //! Count scheduled tests
+ &knot_zone_tests_run //! Run scheduled tests
+};
+
+/*
+ * Unit implementation.
+ */
+
+extern knot_dname_t *dname_from_test_dname(test_dname_t *test_dname);
+extern knot_rrset_t *rrset_from_test_rrset(test_rrset_t *test_rrset);
+
+static knot_node_t *node_from_test_node(const test_node_t *test_node)
+{
+ knot_dname_t *owner = dname_from_test_dname(test_node->owner);
+ /* TODO parent? */
+ knot_node_t *new_node = knot_node_new(owner, NULL, 0);
+ node *n = NULL;
+ WALK_LIST(n, test_node->rrset_list) {
+ test_rrset_t *test_rrset = (test_rrset_t *)n;
+ knot_rrset_t *rrset = rrset_from_test_rrset(test_rrset);
+ assert(rrset);
+ assert(knot_node_add_rrset(new_node, rrset, 0) == 0);
+ }
+
+ return new_node;
+}
+
+static int test_zone_create(list node_list)
+{
+// knot_dname_t *dname = knot_dname_new_from_wire(
+// test_apex.owner.name, test_apex.owner.size, NULL);
+// assert(dname);
+ int errors = 0;
+
+ node *n = NULL;
+ WALK_LIST(n, node_list) {
+ test_node_t *test_node = (test_node_t *)n;
+ knot_node_t *node = node_from_test_node(test_node);
+ assert(node);
+
+ knot_zone_t *zone = knot_zone_new(node, 0, 0);
+ if (zone == NULL) {
+ diag("Could not create zone with owner: %s\n",
+ test_node->owner->str);
+ errors++;
+ }
+ knot_node_free_rrsets(node, 1);
+ knot_node_free(&node, 0, 0);
+ }
+
+ return (errors == 0);
+}
+
+//static int test_zone_add_node(knot_zone_t *zone, int nsec3)
+//{
+// /*
+// * NSEC3 nodes are de facto identical to normal nodes, so there is no
+// * need for separate tests. The only difference is where are they stored
+// * in the zone structure.
+// */
+
+// int errors = 0;
+// int res = 0;
+
+// //note("Good nodes");
+
+// for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+// knot_node_t *node = knot_node_new(&test_nodes_good[i].owner,
+// test_nodes_good[i].parent);
+// if (node == NULL) {
+// diag("zone: Could not create node.");
+// return 0;
+// }
+
+// if ((res = ((nsec3) ? knot_zone_add_nsec3_node(zone, node)
+// : knot_zone_add_node(zone, node))) != 0) {
+// diag("zone: Failed to insert node into zone (returned"
+// " %d).", res);
+// knot_node_free(&node, 0);
+// ++errors;
+// }
+// /* TODO check values in the node as well */
+// }
+
+// //note("Bad nodes");
+
+// for (int i = 0; i < TEST_NODES_BAD; ++i) {
+// knot_node_t *node = knot_node_new(&test_nodes_bad[i].owner,
+// test_nodes_bad[i].parent);
+// if (node == NULL) {
+// diag("zone: Could not create node.");
+// return 0;
+// }
+
+// if ((res = ((nsec3) ? knot_zone_add_nsec3_node(zone, node)
+// : knot_zone_add_node(zone, node))) !=
+// KNOT_EBADZONE) {
+// diag("zone: Inserting wrong node did not result in"
+// "proper return value (%d instead of %d).", res,
+// KNOT_EBADZONE);
+// ++errors;
+// }
+// knot_node_free(&node, 0);
+// }
+
+// // check if all nodes are inserted
+// //int nodes = 0;
+// if (!nsec3
+// && !test_zone_check_node(knot_zone_apex(zone), &test_apex)) {
+// diag("zone: Apex of zone not right.");
+//// diag("Apex owner: %s (%p), apex parent: %p\n",
+//// knot_dname_to_str(knot_zone_apex(zone)->owner),
+//// knot_zone_apex(zone)->owner,
+//// knot_zone_apex(zone)->parent);
+//// diag("Should be: owner: %s (%p), parent: %p\n",
+//// knot_dname_to_str(&test_apex.owner),
+//// &test_apex.owner,
+//// test_apex.parent);
+// ++errors;
+// }
+// //++nodes;
+// for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+// const knot_node_t *n = ((nsec3) ? knot_zone_find_nsec3_node(
+// zone, &test_nodes_good[i].owner) :
+// knot_zone_find_node(zone, &test_nodes_good[i].owner));
+// if (n == NULL) {
+// diag("zone: Missing node with owner %s",
+// test_nodes_good[i].owner.name);
+// ++errors;
+// continue;
+// }
+
+// if (!test_zone_check_node(n, &test_nodes_good[i])) {
+// diag("zone: Node does not match: owner: %s (should be "
+// "%s), parent: %p (should be %p)",
+// node->owner->name, test_nodes_good[i].owner.name,
+// node->parent, test_nodes_good[i].parent);
+// ++errors;
+// }
+// //++nodes;
+// }
+
+// //note("zone: %d nodes in the zone (including apex)", nodes);
+
+// return (errors == 0);
+//}
+
+//static int test_zone_get_node(knot_zone_t *zone, int nsec3)
+//{
+// int errors = 0;
+
+// for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+// if (((nsec3) ? knot_zone_get_nsec3_node(
+// zone, &test_nodes_good[i].owner)
+// : knot_zone_get_node(zone, &test_nodes_good[i].owner))
+// == NULL) {
+// diag("zone: Node (%s) not found in zone.",
+// (char *)test_nodes_good[i].owner.name);
+// ++errors;
+// }
+// }
+
+// for (int i = 0; i < TEST_NODES_BAD; ++i) {
+// if (((nsec3) ? knot_zone_get_nsec3_node(
+// zone, &test_nodes_bad[i].owner)
+// : knot_zone_get_node(zone, &test_nodes_bad[i].owner))
+// != NULL) {
+// diag("zone: Node (%s) found in zone even if it should"
+// "not be there.",
+// (char *)test_nodes_bad[i].owner.name);
+// ++errors;
+// }
+// }
+
+// if (((nsec3)
+// ? knot_zone_get_nsec3_node(NULL, &test_nodes_good[0].owner)
+// : knot_zone_get_node(NULL, &test_nodes_good[0].owner)) != NULL) {
+// diag("zone: Getting node from NULL zone did not result in"
+// "proper return value (NULL)");
+// ++errors;
+// }
+
+// if (((nsec3) ? knot_zone_get_nsec3_node(zone, NULL)
+// : knot_zone_get_node(zone, NULL)) != NULL) {
+// diag("zone: Getting node with NULL owner from zone did not "
+// "result in proper return value (NULL)");
+// ++errors;
+// }
+
+// if (!nsec3 && knot_zone_get_node(zone, &test_apex.owner) == NULL) {
+// diag("zone: Getting zone apex from the zone failed");
+// ++errors;
+// }
+
+// return (errors == 0);
+//}
+
+//static int test_zone_find_node(knot_zone_t *zone, int nsec3)
+//{
+// int errors = 0;
+
+// for (int i = 0; i < TEST_NODES_GOOD; ++i) {
+// if (((nsec3) ? knot_zone_find_nsec3_node(
+// zone, &test_nodes_good[i].owner)
+// : knot_zone_find_node(zone, &test_nodes_good[i].owner))
+// == NULL) {
+// diag("zone: Node (%s) not found in zone.",
+// (char *)test_nodes_good[i].owner.name);
+// ++errors;
+// }
+// }
+
+// for (int i = 0; i < TEST_NODES_BAD; ++i) {
+// if (((nsec3) ? knot_zone_find_nsec3_node(
+// zone, &test_nodes_bad[i].owner)
+// : knot_zone_find_node(zone, &test_nodes_bad[i].owner))
+// != NULL) {
+// diag("zone: Node (%s) found in zone even if it should"
+// "not be there.",
+// (char *)test_nodes_bad[i].owner.name);
+// ++errors;
+// }
+// }
+
+// if (((nsec3)
+// ? knot_zone_find_nsec3_node(NULL, &test_nodes_good[0].owner)
+// : knot_zone_find_node(NULL, &test_nodes_good[0].owner)) != NULL) {
+// diag("zone: Finding node from NULL zone did not result in"
+// "proper return value (NULL)");
+// ++errors;
+// }
+
+// if (((nsec3) ? knot_zone_find_nsec3_node(zone, NULL)
+// : knot_zone_find_node(zone, NULL)) != NULL) {
+// diag("zone: Finding node with NULL owner from zone did not "
+// "result in proper return value (NULL)");
+// ++errors;
+// }
+
+// if (!nsec3 && knot_zone_find_node(zone, &test_apex.owner) == NULL) {
+// diag("zone: Finding zone apex from the zone failed");
+// ++errors;
+// }
+
+// return (errors == 0);
+//}
+
+static const int KNOT_ZONE_TEST_COUNT = 1;
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int knot_zone_tests_count(int argc, char *argv[])
+{
+ return KNOT_ZONE_TEST_COUNT;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int knot_zone_tests_run(int argc, char *argv[])
+{
+ int res = 0,
+ res_final = 0;
+
+ test_data_t *data = data_for_knot_tests;
+
+ ok((res = test_zone_create(data->node_list)), "zone: create");
+ res_final *= res;
+
+// skip(!res, 6);
+
+// ok((res = test_zone_add_node(zone, 0)), "zone: add node");
+// res_final *= res;
+
+// skip(!res, 2);
+
+// skip(!res, 1);
+
+// ok((res = test_zone_find_node(zone, 0)), "zone: find node");
+// res_final *= res;
+
+// endskip; // get node failed
+
+// endskip; // add node failed
+
+// ok((res = test_zone_add_node(zone, 1)), "zone: add nsec3 node");
+// res_final *= res;
+
+// skip(!res, 2);
+
+// skip(!res, 1);
+
+// ok((res = test_zone_find_node(zone, 1)), "zone: find nsec3 node");
+// res_final *= res;
+
+// endskip; // get nsec3 node failed
+
+// endskip; // add nsec3 node failed
+
+// endskip; // create failed
+
+ return res_final;
+}
diff --git a/src/tests/libknot/realdata/libknot/zone_tests_realdata.h b/src/tests/libknot/realdata/libknot/zone_tests_realdata.h
new file mode 100644
index 0000000..5539709
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/zone_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_ZONE_TESTS_H_
+#define _KNOTD_ZONE_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zone_tests_api;
+
+#endif /* _KNOTD_ZONE_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c
new file mode 100644
index 0000000..96d1517
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tests/libknot/realdata/libknot/zonedb_tests_realdata.h"
+
+
+static int zonedb_tests_count(int argc, char *argv[]);
+static int zonedb_tests_run(int argc, char *argv[]);
+
+/*! Exported unit API.
+ */
+unit_api zonedb_tests_api = {
+ "Zone database", //! Unit name
+ &zonedb_tests_count, //! Count scheduled tests
+ &zonedb_tests_run //! Run scheduled tests
+};
+
+/*! This helper routine should report number of
+ * scheduled tests for given parameters.
+ */
+static int zonedb_tests_count(int argc, char *argv[])
+{
+ return 0;
+}
+
+/*! Run all scheduled tests for given parameters.
+ */
+static int zonedb_tests_run(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h
new file mode 100644
index 0000000..0c4f8ef
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_ZONEDB_TESTS_H_
+#define _KNOTD_ZONEDB_TESTS_H_
+
+#include "common/libtap/tap_unit.h"
+
+/* Unit API. */
+unit_api zonedb_tests_api;
+
+#endif /* _KNOTD_ZONEDB_TESTS_H_ */
diff --git a/src/tests/libknot/realdata/libknot_tests_loader_realdata.c b/src/tests/libknot/realdata/libknot_tests_loader_realdata.c
new file mode 100644
index 0000000..71a9c3d
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot_tests_loader_realdata.c
@@ -0,0 +1,1300 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "common/libtap/tap.h"
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+#include "libknot/util/descriptor.h"
+
+#include "tests/libknot/realdata/parsed_data.rc"
+#include "tests/libknot/realdata/raw_data.rc"
+TREE_DEFINE(test_node, avl);
+
+/* Virtual I/O over memory. */
+static int mem_read(void *dst, size_t n, const char **src,
+ unsigned *remaining)
+{
+// printf("reading %u\n", n);
+ if (n > *remaining) {
+ return 0;
+ }
+
+
+ memcpy(dst, *src, n);
+ *src += n;
+ *remaining -= n;
+// printf("remaining %u\n", *remaining);
+ return 1;
+}
+
+static int load_raw_packets(test_data_t *data, uint32_t *count,
+ const char *src, unsigned src_size)
+{
+
+ uint16_t tmp_size = 0;
+
+ /* Packets are stored like this: [size][packet_data]+ */
+
+ if(!mem_read(count, sizeof(uint32_t), &src, &src_size)) {
+ return -1;
+ }
+
+ for (int i = 0; i < *count; i++) {
+ uint16_t query = 0;
+ if (!mem_read(&query, sizeof(query), &src, &src_size)) {
+ return -1;
+ }
+
+ if(!mem_read(&tmp_size, sizeof(uint16_t), &src, &src_size)) {
+ return -1;
+ }
+
+ test_raw_packet_t *packet = malloc(sizeof(test_raw_packet_t));
+
+
+ packet->size = tmp_size;
+ packet->data = malloc(sizeof(uint8_t) * (tmp_size));
+ if(!mem_read(packet->data,
+ sizeof(uint8_t) * tmp_size, &src, &src_size)) {
+ return -1;
+ }
+
+ if (query) {
+ add_tail(&data->raw_query_list, (void *)packet);
+ } else {
+ add_tail(&data->raw_response_list, (void *)packet);
+ }
+
+ test_raw_packet_t *new_packet =
+ malloc(sizeof(test_raw_packet_t));
+ assert(new_packet);
+ new_packet->data = packet->data;
+ new_packet->size = packet->size;
+
+ add_tail(&data->raw_packet_list, (void *)new_packet);
+ }
+
+ return 0;
+}
+
+/* Returns size of type where avalailable */
+size_t wireformat_size_load(uint wire_type)
+{
+ switch(wire_type) {
+ case KNOT_RDATA_WF_BYTE:
+ return 1;
+ break;
+ case KNOT_RDATA_WF_SHORT:
+ return 2;
+ break;
+ case KNOT_RDATA_WF_LONG:
+ return 4;
+ break;
+ case KNOT_RDATA_WF_A:
+ return 4;
+ break;
+ case KNOT_RDATA_WF_AAAA:
+ return 16;
+ break;
+ default: /* unknown size */
+ return 0;
+ break;
+ } /* switch */
+}
+
+static int add_label(uint8_t **labels, const uint8_t label,
+ uint *label_count)
+{
+ void *ret = realloc(*labels, sizeof(uint8_t) * (*label_count + 1));
+ if (ret == NULL) {
+ return -1;
+ }
+
+ *labels = ret;
+ (*labels)[(*label_count)++] = label;
+
+ return 0;
+}
+/* Dnames are stored label by label in the dump */
+/* TODO STRING AS WELL */
+static test_dname_t *load_test_dname(const char **src,
+ unsigned *src_size)
+{
+ test_dname_t *ret = malloc(sizeof(test_dname_t));
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ ret->size = 0;
+ ret->str = NULL;
+ ret->labels = NULL;
+ ret->wire = NULL;
+ ret->label_count = 0;
+ ret->next = NULL;
+ ret->prev = NULL;
+
+ uint8_t label_size = 0;
+ uint8_t *label_wire = NULL;
+ uint8_t *labels = NULL;
+ char *dname_str = NULL;
+ uint label_count = 0;
+ uint dname_length = 0;
+ do {
+ /* Read label size */
+ if (!mem_read(&label_size,
+ sizeof(uint8_t),
+ src,
+ src_size)) {
+ fprintf(stderr, "Faulty read\n");
+ return NULL;
+ }
+
+// diag("%d", label_size);
+
+ add_label(&labels, ret->size, &label_count);
+
+ dname_length += label_size + 1;
+
+ label_wire = malloc(sizeof(uint8_t) * (label_size + 2));
+
+ if (label_wire == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret);
+ return NULL;
+ }
+
+ label_wire[0] = label_size;
+
+ /* Read label wire */
+ if (!mem_read(label_wire + 1,
+ sizeof(uint8_t) *
+ label_size,
+ src,
+ src_size)) {
+ free(label_wire);
+ fprintf(stderr, "Faulty read\n");
+ return NULL;
+ }
+
+ label_wire[label_size + 1] = '\0';
+
+ dname_str = malloc(sizeof(char) * (label_size + 2));
+
+ if (label_size != 0) {
+ /* n - 1 : . */
+ dname_str[label_size] = '.';
+ dname_str[label_size + 1] = '\0';
+
+ memcpy(dname_str, label_wire + 1, label_size);
+ }
+
+ if (ret->size == 0) {
+ ret->wire = malloc(sizeof(uint8_t) * (label_size + 2));
+ if (ret->wire == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret);
+ return NULL;
+ }
+
+ memcpy(ret->wire, label_wire, label_size + 2);
+
+ if (label_size != 0) {
+
+ ret->str =
+ malloc(sizeof(char) * (label_size + 2));
+ if (ret->str == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret->wire);
+ free(ret);
+ return NULL;
+ }
+
+ memcpy(ret->str, dname_str, label_size + 2);
+ }
+
+ ret->size = label_size + 2;
+ } else {
+ /* Concatenate */
+ void *p = realloc(ret->wire,
+ ret->size + (label_size + 2));
+ if (p == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret->wire);
+ free(ret->labels);
+ free(ret);
+ return NULL;
+ }
+ ret->wire = p;
+
+ /* TODO Safe concat? But I set the values myself, right? */
+ /* or maybe memcpy... */
+ strcat((char *)ret->wire, (char *)label_wire);
+ assert(ret->wire);
+
+
+ if (label_size != 0) {
+
+ p = realloc(ret->str,
+ ret->size + (label_size + 2));
+ if (p == NULL) {
+ ERR_ALLOC_FAILED;
+ free(ret->wire);
+ free(ret->str);
+ free(ret->labels);
+ free(ret);
+ return NULL;
+ }
+ ret->str = p;
+
+ strcat(ret->str, dname_str);
+ assert(ret->str);
+ }
+
+ ret->size += label_size + 2;
+ }
+
+ free(label_wire);
+ free(dname_str);
+
+ } while (label_size != 0);
+
+ /*!< \warning even wireformat is ended with 0 every time !!! */
+
+ /* Root domain */
+// if (ret->size == 0) {
+// assert(ret->wire == NULL);
+
+// ret->wire = malloc(sizeof(uint8_t) * 1);
+// if (ret->wire == NULL) {
+// ERR_ALLOC_FAILED;
+// free(ret);
+// return NULL;
+// }
+
+// ret->wire[0] = '\0';
+
+// ret->labels = malloc(sizeof(uint8_t) * 1);
+// if (ret->labels == NULL) {
+// ERR_ALLOC_FAILED;
+// free(ret->wire);
+// free(ret);
+// return NULL;
+// }
+
+// ret->labels[0] = '\0';
+// ret->label_count = 1;
+// }
+
+// printf("OK: %s (%d)\n",ret->str, ret->size);
+
+ ret->labels = labels;
+ ret->size = ret->size - (label_count);
+ ret->label_count = --label_count;
+ ret->next = NULL;
+ ret->prev = NULL;
+
+ assert(ret != NULL);
+
+ return ret;
+}
+
+/*!
+ * \brief Reads dname label by label
+ */
+static test_rdata_t *load_response_rdata(uint16_t type,
+ const char **src,
+ unsigned *src_size)
+{
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "reading rdata for type: %s\n",
+ knot_rrtype_to_string(type));
+#endif
+ /*
+ * Binary format of rdata is as following:
+ * [total_length(except for some types) - see below][rdata_item]+
+ * Dname items are read label by label
+ */
+
+ test_rdata_t *rdata = malloc(sizeof(test_rdata_t));
+
+ CHECK_ALLOC_LOG(rdata, NULL);
+
+ rdata->count = 0;
+ rdata->items = NULL;
+ rdata->type = 0;
+
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ assert(desc != NULL);
+
+ rdata->type = type;
+
+ test_item_t *items =
+ malloc(sizeof(test_item_t) * desc->length);
+
+ if (items == NULL) {
+ ERR_ALLOC_FAILED;
+ free(rdata);
+ return NULL;
+ }
+
+ /* TODO consider realloc */
+
+ uint16_t total_raw_data_length = 0;
+ uint8_t raw_data_length;
+
+ /*
+ * These types have no length, unfortunatelly (python library
+ * does not provide this)
+ */
+ /* TODO the are more types with no length for sure ... */
+
+ if (type != KNOT_RRTYPE_A &&
+ type != KNOT_RRTYPE_NS &&
+ type != KNOT_RRTYPE_AAAA) {
+ if (!mem_read(&total_raw_data_length,
+ sizeof(total_raw_data_length), src, src_size)) {
+ free(rdata);
+ free(items);
+ fprintf(stderr, "Faulty read\n");
+ return NULL;
+ }
+ }
+
+ size_t total_read = 0;
+
+ int i;
+
+ /*
+ * TODO save number of items
+ * in the dump - of minor importance, however
+ */
+ for (i = 0; i < desc->length; i++) {
+ if ((desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME)) {
+ unsigned tmp_remaining = *src_size;
+ items[i].dname = load_test_dname(src, src_size);
+
+ if (items[i].dname == NULL) {
+ fprintf(stderr, "Could not load DNAME!\n");
+ free(rdata);
+ free(items);
+
+ /* TODO something like Marek's purge */
+
+ return NULL;
+ }
+
+// diag("Created DNAME %p item: %d %s %s\n",
+// items[i].dname, i, knot_rrtype_to_string(type),
+// items[i].dname->str);
+
+ rdata->count++;
+ items[i].type = TEST_ITEM_DNAME;
+ items[i].raw_data = NULL;
+ total_read += tmp_remaining - *src_size;
+ } else {
+ if (desc->wireformat[i] ==
+ KNOT_RDATA_WF_BINARYWITHLENGTH) {
+ if (!mem_read(&raw_data_length,
+ sizeof(raw_data_length), src, src_size)) {
+ return NULL;
+ }
+
+ total_read++;
+
+ items[i].raw_data =
+ malloc(sizeof(uint8_t) *
+ (raw_data_length + 3));
+
+ items[i].raw_data[0] =
+ (uint16_t) raw_data_length + 1;
+
+ /* let's store the length again */
+
+ ((uint8_t *)items[i].raw_data)[2] =
+ raw_data_length;
+
+ if (!mem_read(((uint8_t *)
+ items[i].raw_data) + 3,
+ sizeof(uint8_t) * (raw_data_length),
+ src, src_size)) {
+ fprintf(stderr, "Wrong read!\n");
+ return NULL;
+ }
+
+ rdata->count++;
+ items[i].type = TEST_ITEM_RAW_DATA;
+ items[i].dname = NULL;
+ total_read += sizeof(uint8_t) * raw_data_length;
+/* printf("read len (from wire): %d\n",
+ items[i].raw_data[0]);
+ hex_print((char *)items[i].raw_data + 1,
+ items[i].raw_data[0]);
+ */
+ } else {
+ /* Other type than dname or BINARYWITHLENGTH */
+ /* Set dname to NULL */
+ items[i].dname = NULL;
+
+ uint16_t size_fr_desc =
+ (uint16_t)
+ wireformat_size_load(desc->wireformat[i]);
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "reading %d\n", size_fr_desc);
+#endif
+
+ if (size_fr_desc == 0) { /* unknown length */
+/* size_fr_desc = wireformat_size_n(type,
+ items,
+ i);
+ */
+ if ((i != desc->length - 1) &&
+ desc->wireformat[i] !=
+ KNOT_RDATA_WF_TEXT ) {
+ fprintf(stderr,
+ "I dont know how "
+ "to parse this type: %d\n",
+ type);
+ return NULL;
+ } else {
+ size_fr_desc =
+ total_raw_data_length -
+ total_read;
+ if (desc->wireformat[i] ==
+ KNOT_RDATA_WF_TEXT) {
+ break;
+ }
+
+// fprintf(stderr,
+// "Guessed size: %d"
+// " for type: %s"
+// " and index: %d\n",
+// size_fr_desc,
+// knot_rrtype_to_string(type),
+// i);
+ }
+ }
+
+ items[i].raw_data =
+ malloc(sizeof(uint8_t) * size_fr_desc + 2);
+
+// diag("creating raw_data for item %d type %s %p\n",
+// i, knot_rrtype_to_string(type),
+// items[i].raw_data);
+
+ if (items[i].raw_data == NULL) {
+ ERR_ALLOC_FAILED;
+ free(rdata);
+ free(items);
+ return NULL;
+ }
+
+ items[i].raw_data[0] = size_fr_desc;
+
+ if (!mem_read(items[i].raw_data + 1,
+ size_fr_desc,
+ src, src_size)) {
+ fprintf(stderr, "Wrong read\n!");
+ return NULL;
+ }
+
+ rdata->count++;
+ items[i].type = TEST_ITEM_RAW_DATA;
+ items[i].dname = NULL;
+ total_read += size_fr_desc;
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr,
+ "read len (from descriptor): %d\n",
+ items[i].raw_data[0]);
+/* hex_print((char *)items[i].raw_data + 1,
+ items[i].raw_data[0]); */
+
+ if (desc->zoneformat[i] ==
+ KNOT_RDATA_ZF_ALGORITHM) {
+ hex_print((char *)items[i].raw_data,
+ items[i].raw_data[0] + 2);
+ } else {
+ hex_print((char *)items[i].raw_data,
+ items[i].raw_data[0] + 2);
+ }
+#endif
+ }
+ }
+ }
+
+/* if (knot_rdata_set_items(rdata, items, i) != 0) {
+ diag("Error: could not set items\n");
+ return NULL;
+ } */
+
+ rdata->items = items;
+
+ return rdata;
+}
+
+static test_rrset_t *load_response_rrset(const char **src, unsigned *src_size,
+ char is_question)
+{
+ test_rrset_t *rrset = NULL;
+ uint16_t rrset_type = 0;
+ uint16_t rrset_class = 0;
+ uint32_t rrset_ttl = 0;
+
+ /* Each rrset will only have one rdata entry */
+
+ /*
+ * RRSIGs will be read as separate RRSets because that's the way they
+ * are stored in responses
+ */
+
+ /* Read owner first */
+
+ uint8_t dname_size;
+// uint8_t *dname_wire = NULL;
+
+ rrset = malloc(sizeof(test_rrset_t));
+
+ rrset->rrsigs = NULL;
+
+ CHECK_ALLOC_LOG(rrset, NULL);
+
+ init_list(&rrset->rdata_list);
+
+ /* TODO change in dump, size is useless now! */
+ if (!mem_read(&dname_size, sizeof(dname_size), src, src_size)) {
+ free(rrset);
+ return NULL;
+ }
+
+/* dname_wire = malloc(sizeof(uint8_t) * dname_size);
+
+ CHECK_ALLOC_LOG(dname_wire, NULL);
+
+ if (!mem_read(dname_wire, sizeof(uint8_t) * dname_size, src,
+ src_size)) {
+ free(dname_wire);
+ return NULL;
+ } */
+
+ test_dname_t *owner = load_test_dname(src, src_size);
+
+ if (owner == NULL) {
+ free(rrset);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ {
+ fprintf(stderr, "Got owner: %s", owner->str);
+ }
+#endif
+ /* Read other data */
+
+ if (!mem_read(&rrset_type, sizeof(rrset_type), src, src_size)) {
+ return NULL;
+ }
+
+ if (!mem_read(&rrset_class, sizeof(rrset_class), src, src_size)) {
+ return NULL;
+ }
+
+ if (!is_question) {
+ if (!mem_read(&rrset_ttl, sizeof(rrset_ttl), src, src_size)) {
+ return NULL;
+ }
+ } else {
+ rrset_ttl = 0;
+ }
+
+// rrset = knot_rrset_new(owner, rrset_type, rrset_class, rrset_ttl);
+
+ rrset->owner = owner;
+ rrset->type = rrset_type;
+ rrset->rclass = rrset_class;
+ rrset->ttl = rrset_ttl;
+
+ /* Question rrsets have no rdata */
+
+ if (!is_question) {
+ test_rdata_t *tmp_rdata;
+
+ tmp_rdata = load_response_rdata(rrset->type, src, src_size);
+
+ if (tmp_rdata == NULL) {
+ fprintf(stderr,
+ "Could not load rrset rdata - type: %d",
+ rrset->type);
+ free(rrset);
+ return NULL;
+ }
+
+ assert(tmp_rdata->type == rrset->type);
+
+ add_tail(&rrset->rdata_list, (node *)tmp_rdata);
+ }
+
+ return rrset;
+}
+
+static test_response_t *load_parsed_response(const char **src,
+ unsigned *src_size)
+{
+ /* Loads parsed response/query from binary format,
+ * which is as following:
+ * [id][qdcount][ancount][nscount][arcount]
+ * [question_rrset+][answer_rrset+][authority_rrset+]
+ * [additional_rrset]+
+ */
+
+ test_response_t *resp = malloc(sizeof(test_response_t));
+
+ CHECK_ALLOC_LOG(resp, NULL);
+
+ if (!mem_read(&resp->id, sizeof(resp->id), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "id %d\n", resp->id);
+#endif
+
+ if (!mem_read(&resp->qdcount, sizeof(resp->qdcount), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "qdcount: %d\n", resp->qdcount);
+#endif
+
+ if (!mem_read(&resp->ancount, sizeof(resp->ancount), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "ancount: %d\n", resp->ancount);
+#endif
+
+ if (!mem_read(&resp->nscount, sizeof(resp->nscount), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "nscount: %d\n", resp->nscount);
+#endif
+
+ if (!mem_read(&resp->arcount, sizeof(resp->arcount), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+#ifdef RESP_TEST_DEBUG
+ fprintf(stderr, "arcount: %d\n", resp->arcount);
+#endif
+
+ if (!mem_read(&resp->query, sizeof(resp->query), src, src_size)) {
+ free(resp);
+ return NULL;
+ }
+
+ test_rrset_t **question_rrsets;
+
+ question_rrsets = malloc(sizeof(test_rrset_t *) * resp->qdcount);
+
+ for (int i = 0; i < resp->qdcount; i++) {
+ question_rrsets[i] = load_response_rrset(src, src_size, 1);
+ if (question_rrsets[i] == NULL) {
+ fprintf(stderr, "Could not load question rrsets\n");
+
+ for (int j = 0; j < i; j++) {
+ free(question_rrsets[i]);
+ }
+ free(question_rrsets);
+ free(resp);
+ return NULL;
+ }
+ }
+
+ /* only one question in our case */
+
+ resp->qname = question_rrsets[0]->owner;
+ resp->qtype = question_rrsets[0]->type;
+ resp->qclass = question_rrsets[0]->rclass;
+
+ resp->question = NULL;
+
+/* for (int i = 0; i < resp->qdcount; i++) {
+ knot_rrset_free(&(question_rrsets[i]));
+ } */
+
+ free(question_rrsets);
+
+ test_rrset_t *tmp_rrset = NULL;
+
+ if (resp->ancount > 0) {
+ resp->answer =
+ malloc(sizeof(test_rrset_t *) * resp->ancount);
+ } else {
+ resp->answer = NULL;
+ }
+
+ for (int i = 0; i < resp->ancount; i++) {
+ tmp_rrset = load_response_rrset(src, src_size, 0);
+ resp->answer[i] = tmp_rrset;
+ if (resp->answer[i] == NULL) {
+ fprintf(stderr, "Could not load answer rrsets\n");
+ free(resp->answer);
+ free(resp);
+ return NULL;
+ }
+ }
+
+ if (resp->nscount > 0) {
+ resp->authority =
+ malloc(sizeof(test_rrset_t *) * resp->nscount);
+ } else {
+ resp->authority = NULL;
+ }
+
+ for (int i = 0; i < resp->nscount; i++) {
+ tmp_rrset = load_response_rrset(src, src_size, 0);
+ resp->authority[i] = tmp_rrset;
+ if (resp->authority[i] == NULL) {
+ fprintf(stderr, "Could not load authority rrsets\n");
+ free(resp->authority);
+ free(resp->answer);
+ free(resp);
+ return NULL;
+ }
+ }
+
+ if (resp->arcount > 0) {
+ resp->additional =
+ malloc(sizeof(test_rrset_t *) * resp->arcount);
+ } else {
+ resp->additional = NULL;
+ }
+
+ for (int i = 0; i < resp->arcount; i++) {
+ tmp_rrset = load_response_rrset(src, src_size, 0);
+ if (tmp_rrset == NULL) {
+ fprintf(stderr, "Could not load rrset (additional)\n");
+ free(resp->additional);
+ free(resp->authority);
+ free(resp->answer);
+ free(resp);
+ return NULL;
+ }
+
+ resp->additional[i] = tmp_rrset;
+ }
+
+ /* this will never be used */
+
+ resp->flags1 = 0;
+ resp->flags2 = 0;
+
+ return resp;
+}
+
+static void test_dname_free(test_dname_t **dname)
+{
+ assert(dname != NULL && *dname != NULL);
+ free((*dname)->labels);
+// free((*dname)->str);
+ free((*dname)->wire);
+
+ free(*dname);
+ *dname = NULL;
+}
+
+static int wire_is_dname(uint type)
+{
+ return (type == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ type == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ type == KNOT_RDATA_WF_LITERAL_DNAME);
+}
+
+static void test_rdata_free(test_rdata_t **rdata)
+{
+ assert(rdata != NULL && *rdata != NULL);
+
+ /* Free all the items */
+ const knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type((*rdata)->type);
+
+ for (int i = 0; i < (*rdata)->count; i++) {
+ if ((wire_is_dname(desc->wireformat[i])) &&
+ ((*rdata)->items[i].dname != NULL)) {
+ test_dname_free(&(*rdata)->items[i].dname);
+ } else if ((*rdata)->items[i].raw_data != NULL) {
+ free((*rdata)->items[i].raw_data);
+ (*rdata)->items[i].raw_data = NULL;
+ }
+ }
+// free((*rdata)->items);
+// free(*rdata);
+ *rdata = NULL;
+}
+
+static void test_rrset_free(test_rrset_t **rrset)
+{
+ assert(rrset && *rrset);
+
+ test_dname_free(&(*rrset)->owner);
+ /* Free all the rdatas */
+ node *n = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(n, nxt, (*rrset)->rdata_list) {
+ test_rdata_t *tmp_rdata = (test_rdata_t *)n;
+ assert(tmp_rdata);
+ if (tmp_rdata != NULL) {
+ test_rdata_free(&tmp_rdata);
+ }
+ }
+
+ free(*rrset);
+ *rrset = NULL;
+}
+
+static void test_response_free(test_response_t **response)
+{
+ assert(response && *response);
+ if ((*response)->qname != NULL) {
+ test_dname_free(&(*response)->qname);
+ }
+
+ if ((*response)->additional != NULL) {
+ for (int j = 0; j < (*response)->arcount; j++) {
+ test_rrset_free(&((*response)->additional[j]));
+ }
+
+ free((*response)->additional);
+ }
+
+ if ((*response)->answer != NULL) {
+ for (int j = 0; j < (*response)->ancount; j++) {
+ test_rrset_free(&((*response)->answer[j]));
+ }
+
+ free((*response)->answer);
+ }
+
+ if ((*response)->authority != NULL) {
+ for (int j = 0; j < (*response)->nscount; j++) {
+ test_rrset_free(&((*response)->authority[j]));
+ }
+
+ free((*response)->authority);
+ }
+
+ free((*response));
+ *response = NULL;
+}
+
+static void get_and_save_data_from_rdata(test_rdata_t *rdata,
+ test_data_t *data, uint16_t type)
+{
+ /* We only want to extract dnames */
+ const knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+
+ if (rdata->count == 0) {
+// diag("Rdata count not set!\n");
+ rdata->count = desc->length;
+ }
+
+ for(int i = 0; i < rdata->count; i++) {
+ if ((desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME)) {
+ add_tail(&data->dname_list,
+ (node *)rdata->items[i].dname);
+ test_item_t *temp_item = malloc(sizeof(test_item_t));
+ temp_item->dname = rdata->items[i].dname;
+ temp_item->type = TEST_ITEM_DNAME;
+ temp_item->raw_data = NULL;
+ add_tail(&data->item_list, (node *)temp_item);
+ } else {
+ test_item_t *temp_item = malloc(sizeof(test_item_t));
+ temp_item->dname = NULL;
+ temp_item->type = TEST_ITEM_RAW_DATA;
+ temp_item->raw_data = rdata->items[i].raw_data;
+ add_tail(&data->item_list, (node *)temp_item);
+ }
+ }
+}
+
+static void get_and_save_data_from_rrset(const test_rrset_t *rrset,
+ test_data_t *data)
+{
+// knot_rrtype_descriptor_t *desc =
+// knot_rrtype_descriptor_by_type(rrset->type);
+ /* RDATA are in a list. */
+ node *n = NULL;
+ int i = 0;
+ WALK_LIST(n, rrset->rdata_list) {
+ test_rdata_t *tmp_rdata = (test_rdata_t *)n;
+ assert(tmp_rdata);
+ assert(&data->rdata_list);
+ assert(&data->rdata_list != &rrset->rdata_list);
+ assert(tmp_rdata->type == rrset->type);
+
+ test_rdata_t *new_rdata = malloc(sizeof(test_rdata_t));
+ new_rdata->count = tmp_rdata->count;
+ new_rdata->items = tmp_rdata->items;
+ new_rdata->type = tmp_rdata->type;
+
+ add_tail(&data->rdata_list, (node *)new_rdata);
+ get_and_save_data_from_rdata(tmp_rdata, data, rrset->type);
+ i++;
+ }
+ assert(i == 1);
+}
+
+static int add_rrset_to_node(const test_rrset_t *rrset, test_data_t *data)
+{
+ /* First, create node from rrset */
+ test_node_t *tmp_node = malloc(sizeof(test_node_t));
+ memset(tmp_node, 0, sizeof(test_node_t));
+ CHECK_ALLOC_LOG(tmp_node, -1);
+
+ tmp_node->owner = rrset->owner;
+ tmp_node->parent = NULL;
+ tmp_node->rrset_count = 0;
+
+ /* Will not be used in list now */
+ tmp_node->prev = NULL;
+ tmp_node->next = NULL;
+
+
+// printf("%s\n", rrset->owner->wire);
+// getchar();
+
+/* tmp_node->avl_left = NULL;
+ tmp_node->avl_right = NULL;
+ tmp_node->avl_height = 0; */
+
+ test_node_t *found_node =
+ TREE_FIND(data->node_tree, test_node, avl, tmp_node);
+
+ if (found_node == NULL) {
+ /* Insert new node with current rrset */
+ init_list(&tmp_node->rrset_list);
+ add_tail(&tmp_node->rrset_list, (node *)rrset);
+ tmp_node->rrset_count++;
+
+ TREE_INSERT(data->node_tree, test_node, avl, tmp_node);
+ } else {
+ free(tmp_node);
+ /* append rrset */
+
+ add_tail(&found_node->rrset_list, (node *)rrset);
+ found_node->rrset_count++;
+ }
+
+ return 0;
+}
+
+static void get_and_save_data_from_response(const test_response_t *response,
+ test_data_t *data)
+{
+ /* Go through all the rrsets in the response */
+
+ for (int i = 0; i < response->ancount; i++) {
+ assert(response->answer[i]);
+ /* Add rrset to the list of rrsets - there will be duplicates
+ * But not the same pointers */
+ add_tail(&data->rrset_list, (node *)response->answer[i]);
+ get_and_save_data_from_rrset(response->answer[i], data);
+ if (add_rrset_to_node(response->answer[i], data) != 0) {
+ return;
+ }
+ }
+
+ for (int i = 0; i < response->arcount; i++) {
+ /* Add rrset to the list of rrsets - there will be duplicates */
+ assert(response->additional[i]);
+ add_tail(&data->rrset_list, (node *)response->additional[i]);
+ get_and_save_data_from_rrset(response->additional[i], data);
+ if (add_rrset_to_node(response->additional[i], data) != 0) {
+ return;
+ }
+ }
+
+ for (int i = 0; i < response->nscount; i++) {
+ assert(response->authority[i]);
+ /* Add rrset to the list of rrsets - there will be duplicates */
+ add_tail(&data->rrset_list, (node *)response->authority[i]);
+ get_and_save_data_from_rrset(response->authority[i], data);
+ if (add_rrset_to_node(response->authority[i], data) != 0) {
+ return;
+ }
+ }
+
+// for (int i = 0; i < response->qdcount; i++) {
+// /* Add rrset to the list of rrsets - there will be duplicates */
+// add_tail(&data->rrset_list, (node *)response->question[i]);
+// get_and_save_data_from_rrset(response->question[i], data);
+// }
+}
+
+static int load_parsed_responses(test_data_t *data, uint32_t *count,
+ const char* src, unsigned src_size)
+{
+ if (!mem_read(count, sizeof(*count), &src, &src_size)) {
+ fprintf(stderr, "Wrong read\n");
+ return -1;
+ }
+
+// *responses = malloc(sizeof(test_response_t *) * *count);
+
+ for (int i = 0; i < *count; i++) {
+ test_response_t *tmp_response =
+ load_parsed_response(&src, &src_size);
+
+ if (tmp_response == NULL) {
+ fprintf(stderr, "Could not load response - %d"
+ "- returned NULL\n",
+ i);
+ return -1;
+ }
+
+ if (tmp_response->query) {
+ add_tail(&data->query_list, (node *)tmp_response);
+ } else {
+ add_tail(&data->response_list, (node *)tmp_response);
+ }
+
+ /* Create new node */
+ test_response_t *resp = malloc(sizeof(test_response_t));
+ assert(resp);
+ memcpy(resp, tmp_response, sizeof(test_response_t));
+ add_tail(&data->packet_list,
+ (node *)resp);
+ }
+
+ return 0;
+}
+
+//void free_parsed_responses(test_response_t ***responses, uint32_t *count)
+//{
+// if (*responses != NULL) {
+// for (int i = 0; i < *count; i++) {
+// free_parsed_response((*responses)[i]);
+// }
+// free(*responses);
+// }
+//}
+
+static int compare_nodes(test_node_t *node1, test_node_t *node2)
+{
+ assert(node1->owner && node2->owner);
+ /*!< \warning Wires have to be \0 terminated. */
+ return (strcmp((char *)node1->owner->wire, (char *)node2->owner->wire));
+}
+
+static int init_data(test_data_t *data)
+{
+ if (data == NULL) {
+ return 0;
+ }
+
+ /* Initialize all the lists */
+ init_list(&data->dname_list);
+ init_list(&data->edns_list);
+ init_list(&data->node_list);
+ init_list(&data->response_list);
+ init_list(&data->rdata_list);
+ init_list(&data->rrset_list);
+ init_list(&data->item_list);
+ init_list(&data->raw_response_list);
+ init_list(&data->raw_query_list);
+ init_list(&data->raw_packet_list);
+ init_list(&data->query_list);
+ init_list(&data->packet_list);
+
+ data->node_tree = malloc(sizeof(avl_tree_test_t));
+ CHECK_ALLOC_LOG(data->node_tree, 0);
+
+ TREE_INIT(data->node_tree, compare_nodes);
+
+ return 1;
+}
+
+static void print_stats(test_data_t *data)
+{
+ uint resp_count = 0, dname_count = 0, node_count = 0,
+ rdata_count = 0, rrset_count = 0, item_count = 0, query_count = 0,
+ raw_query_count = 0, response_count = 0, packet_count = 0,
+ raw_packet_count = 0, raw_response_count = 0;
+
+ node *n = NULL; /* Will not be used */
+
+ WALK_LIST(n, data->response_list) {
+ resp_count++;
+ }
+
+ WALK_LIST(n, data->rrset_list) {
+// node *tmp = NULL;
+// assert(((test_rrset_t *)n)->owner);
+// WALK_LIST(tmp, ((test_rrset_t *)n)->rdata_list) {
+// test_rdata_t *rdata = (test_rdata_t *)tmp;
+// assert(rdata->type == ((test_rrset_t *)n)->type);
+// }
+ rrset_count++;
+ }
+
+ WALK_LIST(n, data->rdata_list) {
+ rdata_count++;
+ }
+
+ WALK_LIST(n, data->dname_list) {
+ dname_count++;
+ }
+
+ WALK_LIST(n, data->node_list) {
+ node_count++;
+ }
+
+ WALK_LIST(n, data->item_list) {
+ item_count++;
+ }
+
+ WALK_LIST(n, data->raw_response_list) {
+ raw_response_count++;
+ }
+
+ WALK_LIST(n, data->query_list) {
+ query_count++;
+ }
+
+ WALK_LIST(n, data->response_list) {
+ response_count++;
+ }
+
+ WALK_LIST(n, data->raw_query_list) {
+ raw_query_count++;
+ }
+
+ WALK_LIST(n, data->packet_list) {
+ packet_count++;
+ }
+
+ WALK_LIST(n, data->raw_packet_list) {
+ raw_packet_count++;
+ }
+
+ printf("Loaded: Responses: %d RRSets: %d RDATAs: %d Dnames: %d "
+ "Nodes: %d Items: %d Raw_responses: %d Queries: %d \n"
+ "Raw_queries; %d Total packets: %d Total_raw_packets: %d\n", resp_count, rrset_count,
+ rdata_count, dname_count, node_count, item_count,
+ raw_response_count, query_count, raw_query_count, packet_count,
+ raw_packet_count);
+}
+
+static void save_node_to_list(test_node_t *n, void *p)
+{
+ test_data_t *data = (test_data_t *)p;
+
+ add_tail(&data->node_list, (node *)n);
+}
+
+static void del_node(test_node_t *n, void *p)
+{
+// test_data_t *data = (test_data_t *)p;
+ free(n);
+}
+
+
+void free_data(test_data_t **data)
+{
+ assert(data && *data);
+ /* We will free all the data using responses
+ * (others are just references )*/
+ node *n = NULL, *nxt = NULL;
+ WALK_LIST_DELSAFE(n, nxt, (*data)->response_list) {
+ test_response_t *tmp_response = (test_response_t *)n;
+ if (tmp_response != NULL) {
+ test_response_free(&tmp_response);
+ }
+ }
+
+ TREE_POST_ORDER_APPLY((*data)->node_tree, test_node, avl, del_node,
+ NULL);
+
+ free((*data)->node_tree);
+
+ free(*data);
+ *data = NULL;
+}
+
+test_data_t *create_test_data_from_dump()
+{
+ test_data_t *ret = malloc(sizeof(test_data_t));
+ CHECK_ALLOC_LOG(ret, NULL);
+
+ if (!init_data(ret)) {
+ free(ret);
+ return NULL;
+ }
+
+ uint32_t raw_packet_count = 0;
+
+ if (load_raw_packets(ret, &raw_packet_count, raw_data_rc,
+ raw_data_rc_size) != 0) {
+ fprintf(stderr, "Could not load raw_data, quitting");
+ /* TODO walk the lists*/
+ free(ret);
+ return NULL;
+ }
+
+ uint32_t response_count = 0;
+
+ if (load_parsed_responses(ret, &response_count, parsed_data_rc,
+ parsed_data_rc_size) != 0) {
+ fprintf(stderr, "Could not load responses, quitting");
+ /* TODO walk the lists*/
+ free(ret);
+ return NULL;
+ }
+
+ /* For each parsed response - create more data from it. */
+ /* Probably not the most effective way, but it is better than to
+ * rewrite most of the code .*/
+
+ node *n = NULL;
+
+ WALK_LIST(n , ret->response_list) {
+ get_and_save_data_from_response((test_response_t *)n, ret);
+ }
+
+ /* Create list from AVL tree */
+
+ TREE_FORWARD_APPLY(ret->node_tree, test_node, avl,
+ save_node_to_list, ret);
+
+ print_stats(ret);
+
+ return ret;
+}
diff --git a/src/tests/libknot/realdata/libknot_tests_loader_realdata.h b/src/tests/libknot/realdata/libknot_tests_loader_realdata.h
new file mode 100644
index 0000000..8f57944
--- /dev/null
+++ b/src/tests/libknot/realdata/libknot_tests_loader_realdata.h
@@ -0,0 +1,179 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KNOT_TESTS_LOADER_H
+#define KNOT_TESTS_LOADER_H
+
+#include <stdint.h>
+
+#include "libknot/common.h"
+#include "common/lists.h"
+#include "common/tree.h"
+
+
+/* Parsed raw packet*/
+struct test_raw_packet {
+ struct node *next, *prev;
+ uint size;
+ uint8_t *data;
+};
+
+typedef struct test_raw_packet test_raw_packet_t;
+
+/* Test type definitions */
+
+struct test_dname {
+ struct node *next, *prev;
+ char *str;
+ uint8_t *wire;
+ uint size;
+ uint8_t *labels;
+ short label_count;
+};
+
+typedef struct test_dname test_dname_t;
+
+struct test_edns_options {
+ struct node *next, *prev;
+ uint16_t code;
+ uint16_t length;
+ uint8_t *data;
+};
+
+struct test_edns {
+ struct node *next, *prev;
+ struct test_edns_options *options;
+ uint16_t payload;
+ uint8_t ext_rcode;
+ uint8_t version;
+ uint16_t flags;
+ uint16_t *wire;
+ short option_count;
+ short options_max;
+ short size;
+};
+
+typedef struct test_edns test_edns_t;
+
+typedef TREE_HEAD(avl_tree_test, test_node) avl_tree_test_t;
+
+struct test_node {
+ struct node *next, *prev;
+ test_dname_t *owner;
+ short rrset_count;
+ struct test_node *parent;
+ list rrset_list;
+
+ TREE_ENTRY(test_node) avl;
+};
+
+typedef struct test_node test_node_t;
+
+enum item_type {
+ TEST_ITEM_DNAME,
+ TEST_ITEM_RAW_DATA
+};
+
+typedef enum item_type item_type_t;
+
+struct test_item {
+ uint16_t *raw_data;
+ test_dname_t *dname;
+ item_type_t type;
+};
+
+typedef struct test_item test_item_t;
+
+struct test_rdata {
+ struct node *next, *prev;
+ uint count;
+ uint type; /*!< Might be handy */
+ test_item_t *items;
+};
+
+typedef struct test_rdata test_rdata_t;
+
+struct test_rrset {
+ struct node *next, *prev;
+ test_dname_t *owner;
+ uint16_t type;
+ uint16_t rclass;
+ uint32_t ttl;
+ struct test_rrset *rrsigs;
+ uint16_t *wire;
+ list rdata_list;
+};
+
+typedef struct test_rrset test_rrset_t;
+
+struct test_response {
+ struct node *next, *prev;
+ /* This is basically same thing as actual response structure */
+ uint16_t query;
+ test_dname_t *qname;
+ uint16_t qclass;
+ uint16_t qtype;
+ uint16_t id;
+ uint8_t flags1;
+ uint8_t flags2;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+
+ /* Arrays of rrsets */
+
+ test_rrset_t **question;
+ test_rrset_t **answer;
+ test_rrset_t **authority;
+ test_rrset_t **additional;
+
+ short size;
+
+ /* what about the rest of the values?
+ * they cannot be modified from API, but this is probably the best
+ * place to test them as well */
+};
+
+typedef struct test_response test_response_t;
+
+/*!< \brief contains lists of all the structures */
+struct test_data {
+ list dname_list;
+ list edns_list;
+ list rdata_list;
+ list node_list;
+ list rrset_list;
+ list response_list;
+ list raw_response_list;
+ list query_list;
+ list raw_query_list;
+ list item_list;
+ /* responses and queries together */
+ list packet_list;
+ list raw_packet_list;
+
+ avl_tree_test_t *node_tree;
+};
+
+typedef struct test_data test_data_t;
+
+/*!< \brief Parses resource with data and creates all possible structures. */
+test_data_t *create_test_data_from_dump();
+
+test_data_t *data_for_knot_tests;
+
+#endif // KNOT_TESTS_LOADER_H
diff --git a/src/tests/libknot/realdata/unittests_libknot_realdata.c b/src/tests/libknot/realdata/unittests_libknot_realdata.c
new file mode 100644
index 0000000..e557c43
--- /dev/null
+++ b/src/tests/libknot/realdata/unittests_libknot_realdata.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+//#include "knot/common.h"
+#include "common/libtap/tap_unit.h"
+
+#include "tests/libknot/realdata/libknot_tests_loader_realdata.h"
+
+// Units to test
+#include "tests/libknot/realdata/libknot/dname_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/response_tests_realdata.h"
+//#include "libknot/edns_tests.h"
+#include "tests/libknot/realdata/libknot/node_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/rdata_tests_realdata.h"
+//#include "libknot/response_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/rrset_tests_realdata.h"
+//#include "libknot/zone_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/zonedb_tests_realdata.h"
+#include "tests/libknot/realdata/libknot/packet_tests_realdata.h"
+
+#include "common/lists.h"
+// Run all loaded units
+int main(int argc, char *argv[])
+{
+ data_for_knot_tests = create_test_data_from_dump();
+
+ if (data_for_knot_tests == NULL) {
+ diag("Data could not be loaded!");
+ return 0;
+ }
+
+ // Open log
+// log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING));
+
+ // Build test set
+ unit_api *tests[] = {
+
+ /* DNS units */
+// &cuckoo_tests_api, //! Cuckoo hashing unit
+ &dname_tests_api, //! DNS library (dname) unit
+// &edns_tests_api, //! DNS library (EDNS0) unit
+ &node_tests_api, //! DNS library (node) unit
+ &rdata_tests_api, //! DNS library (rdata) unit
+ &packet_tests_api,
+// &response_tests_api, //! DNS library (response) unit
+ &response_tests_api, //! DNS library (response) unit
+ &rrset_tests_api, //! DNS library (rrset) unit
+// &zone_tests_api, //! DNS library (zone) unit
+// &zonedb_tests_api, //! DNS library (zonedb) unit
+ NULL
+ };
+
+ // Plan number of tests
+ int id = 0;
+ int test_count = 0;
+ note("Units:");
+ while (tests[id] != NULL) {
+ note("- %s : %d tests", tests[id]->name,
+ tests[id]->count(argc, argv));
+ test_count += tests[id]->count(argc, argv);
+ ++id;
+ }
+
+ plan(test_count);
+
+ // Run tests
+ id = 0;
+ while (tests[id] != NULL) {
+ diag("Testing unit: %s", tests[id]->name);
+ tests[id]->run(argc, argv);
+ ++id;
+ }
+
+// log_close();
+
+ // Evaluate
+ return exit_status();
+}
+
diff --git a/src/tests/libknot/unittests_libknot.c b/src/tests/libknot/unittests_libknot.c
new file mode 100644
index 0000000..62d4b90
--- /dev/null
+++ b/src/tests/libknot/unittests_libknot.c
@@ -0,0 +1,90 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "knot/common.h"
+#include "common/libtap/tap_unit.h"
+
+// Units to test
+#include "tests/libknot/libknot/cuckoo_tests.h"
+#include "tests/libknot/libknot/dname_tests.h"
+#include "tests/libknot/libknot/edns_tests.h"
+#include "tests/libknot/libknot/node_tests.h"
+#include "tests/libknot/libknot/rdata_tests.h"
+#include "tests/libknot/libknot/response_tests.h"
+#include "tests/libknot/libknot/rrset_tests.h"
+#include "tests/libknot/libknot/zone_tests.h"
+#include "tests/libknot/libknot/dname_table_tests.h"
+#include "tests/libknot/libknot/nsec3_tests.h"
+#include "tests/libknot/libknot/packet_tests.h"
+#include "tests/libknot/libknot/query_tests.h"
+#include "tests/libknot/libknot/zonedb_tests.h"
+#include "tests/libknot/libknot/zone_tree_tests.h"
+
+// Run all loaded units
+int main(int argc, char *argv[])
+{
+ // Open log
+// log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING));
+
+ // Build test set
+ unit_api *tests[] = {
+
+ /* DNS units */
+ &cuckoo_tests_api, //! Cuckoo hashing unit
+ &dname_tests_api, //! DNS library (dname) unit
+ &edns_tests_api, //! DNS library (EDNS0) unit
+ &zone_tests_api, //! DNS library (zone) unit
+ &node_tests_api, //! DNS library (node) unit
+ &rdata_tests_api, //! DNS library (rdata) unit
+ &response_tests_api, //! DNS library (response) unit
+ &rrset_tests_api, //! DNS library (rrset) unit
+ &dname_table_tests_api,
+ &nsec3_tests_api,
+ &packet_tests_api,
+ &query_tests_api,
+ &zonedb_tests_api, //! DNS library (zonedb) unit
+ &zone_tree_tests_api,
+ NULL
+ };
+
+ // Plan number of tests
+ int id = 0;
+ int test_count = 0;
+ note("Units:");
+ while (tests[id] != NULL) {
+ note("- %s : %d tests", tests[id]->name,
+ tests[id]->count(argc, argv));
+ test_count += tests[id]->count(argc, argv);
+ ++id;
+ }
+
+ plan(test_count);
+
+ // Run tests
+ id = 0;
+ while (tests[id] != NULL) {
+ diag("Testing unit: %s", tests[id]->name);
+ tests[id]->run(argc, argv);
+ ++id;
+ }
+
+// log_close();
+
+ // Evaluate
+ return exit_status();
+}
+
diff --git a/src/tests/unittests_main.c b/src/tests/unittests_main.c
new file mode 100644
index 0000000..2d57ed2
--- /dev/null
+++ b/src/tests/unittests_main.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "knot/common.h"
+#include "common/libtap/tap_unit.h"
+
+// Units to test
+#include "tests/common/slab_tests.h"
+#include "tests/common/skiplist_tests.h"
+#include "tests/common/events_tests.h"
+#include "tests/common/da_tests.h"
+#include "tests/common/acl_tests.h"
+#include "tests/common/fdset_tests.h"
+#include "tests/knot/dthreads_tests.h"
+#include "tests/knot/journal_tests.h"
+#include "tests/knot/server_tests.h"
+#include "tests/knot/conf_tests.h"
+
+// Run all loaded units
+int main(int argc, char *argv[])
+{
+ // Open log
+ log_init();
+ log_levels_set(LOGT_SYSLOG, LOG_ANY, 0);
+
+ // Build test set
+ unit_api *tests[] = {
+ /* Core data structures. */
+ &journal_tests_api, //! Journal unit
+ &slab_tests_api, //! SLAB allocator unit
+ &skiplist_tests_api, //! Skip list unit
+ &dthreads_tests_api, //! DThreads testing unit
+ &events_tests_api, //! Events testing unit
+ &da_tests_api, //! Dynamic array unit
+ &acl_tests_api, //! ACLs
+ &fdset_tests_api, //! FDSET polling wrapper
+
+ /* Server parts. */
+ &conf_tests_api, //! Configuration parser tests
+ &server_tests_api, //! Server unit
+ NULL
+ };
+
+ // Plan number of tests
+ int id = 0;
+ int test_count = 0;
+ note("Units:");
+ while (tests[id] != NULL) {
+ note("- %s : %d tests", tests[id]->name,
+ tests[id]->count(argc, argv));
+ test_count += tests[id]->count(argc, argv);
+ ++id;
+ }
+
+ plan(test_count);
+
+ // Run tests
+ id = 0;
+ while (tests[id] != NULL) {
+ diag("Testing unit: %s", tests[id]->name);
+ tests[id]->run(argc, argv);
+ ++id;
+ }
+
+ log_close();
+
+ // Evaluate
+ return exit_status();
+}
+
diff --git a/src/zcompile/LICENSE b/src/zcompile/LICENSE
new file mode 100644
index 0000000..55faacf
--- /dev/null
+++ b/src/zcompile/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
+
+This software is open source.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+Neither the name of the NLNET LABS nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/zcompile/parser-descriptor.c b/src/zcompile/parser-descriptor.c
new file mode 100644
index 0000000..41e7f2d
--- /dev/null
+++ b/src/zcompile/parser-descriptor.c
@@ -0,0 +1,535 @@
+/*!
+ * \file parser-descriptor.c
+ *
+ * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * most of the work by NLnet Labs.
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief Contains resource record descriptor and its API
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/types.h>
+
+//#include "common.h"
+#include "zcompile/parser-descriptor.h"
+/* TODO this has to be removed - move tokens to separate file
+ but can it be done?) */
+#include "zcompile/zcompile.h"
+/* FIXME: Generate .y and .l to zoneparser/ */
+#include "zparser.h"
+
+enum desclen { PARSER_RRTYPE_DESCRIPTORS_LENGTH = 32770 }; // used to be 101
+
+/* Taken from RFC 1035, section 3.2.4. */
+static knot_lookup_table_t dns_rrclasses[] = {
+ { PARSER_CLASS_IN, "IN" }, /* the Internet */
+ { PARSER_CLASS_CS, "CS" }, /* the CSNET class (Obsolete) */
+ { PARSER_CLASS_CH, "CH" }, /* the CHAOS class */
+ { PARSER_CLASS_HS, "HS" }, /* Hesiod */
+ { 0, NULL }
+};
+static parser_rrtype_descriptor_t
+ knot_rrtype_descriptors[PARSER_RRTYPE_DESCRIPTORS_LENGTH] = {
+ /* 0 */
+ { 0, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 1 */
+ { PARSER_RRTYPE_A, T_A, "A", 1, { PARSER_RDATA_WF_A }, true },
+ /* 2 */
+ { PARSER_RRTYPE_NS, T_NS, "NS", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 3 */
+ { PARSER_RRTYPE_MD, T_MD, "MD", 1,
+ { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 4 */
+ { PARSER_RRTYPE_MF, T_MF, "MF", 1,
+ { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 5 */
+ { PARSER_RRTYPE_CNAME, T_CNAME, "CNAME", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 6 */
+ { PARSER_RRTYPE_SOA, T_SOA, "SOA", 7,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME, PARSER_RDATA_WF_COMPRESSED_DNAME,
+ PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG,
+ PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG }, true },
+ /* 7 */
+ { PARSER_RRTYPE_MB, T_MB, "MB", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 8 */
+ { PARSER_RRTYPE_MG, T_MG, "MG", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 9 */
+ { PARSER_RRTYPE_MR, T_MR, "MR", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 10 */
+ { PARSER_RRTYPE_NULL, T_NULL, NULL, 1,
+ { PARSER_RDATA_WF_BINARY }, true },
+ /* 11 */
+ { PARSER_RRTYPE_WKS, T_WKS, "WKS", 2,
+ { PARSER_RDATA_WF_A, PARSER_RDATA_WF_BINARY }, true },
+ /* 12 */
+ { PARSER_RRTYPE_PTR, T_PTR, "PTR", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 13 */
+ { PARSER_RRTYPE_HINFO, T_HINFO, "HINFO", 2,
+ { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, true },
+ /* 14 */
+ { PARSER_RRTYPE_MINFO, T_MINFO, "MINFO", 2,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME,
+ PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 15 */
+ { PARSER_RRTYPE_MX, T_MX, "MX", 2,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 16 */ /* This is obscure, but I guess there's no other way */
+ { PARSER_RRTYPE_TXT, T_TXT, "TXT", PARSER_MAX_RDATA_ITEMS,
+ { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false },
+ /* 17 */
+ { PARSER_RRTYPE_RP, T_RP, "RP", 2,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME,
+ PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 18 */
+ { PARSER_RRTYPE_AFSDB, T_AFSDB, "AFSDB", 2,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 19 */
+ { PARSER_RRTYPE_X25, T_X25, "X25", 1,
+ { PARSER_RDATA_WF_TEXT }, true },
+ /* 20 */
+ { PARSER_RRTYPE_ISDN, T_ISDN, "ISDN", 2,
+ { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false },
+ /* 21 */
+ { PARSER_RRTYPE_RT, T_RT, "RT", 2,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 22 */
+ { PARSER_RRTYPE_NSAP, T_NSAP, "NSAP", 1,
+ { PARSER_RDATA_WF_BINARY }, true },
+ /* 23 */
+ { 23, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 24 */
+ { PARSER_RRTYPE_SIG, T_SIG, "SIG", 9,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG,
+ PARSER_RDATA_WF_SHORT,PARSER_RDATA_WF_UNCOMPRESSED_DNAME,
+ PARSER_RDATA_WF_BINARY }, true },
+ /* 25 */
+ { PARSER_RRTYPE_KEY, T_KEY, "KEY", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true },
+ /* 26 */
+ { PARSER_RRTYPE_PX, T_PX, "PX", 3,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_UNCOMPRESSED_DNAME,
+ PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 27 */
+ { 27, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 28 */
+ { PARSER_RRTYPE_AAAA, T_AAAA, "AAAA", 1,
+ { PARSER_RDATA_WF_AAAA }, true },
+ /* 29 */
+ { PARSER_RRTYPE_LOC, T_LOC, "LOC", 1,
+ { PARSER_RDATA_WF_BINARY }, true },
+ /* 30 */
+ { PARSER_RRTYPE_NXT, T_NXT, "NXT", 2,
+ { PARSER_RDATA_WF_UNCOMPRESSED_DNAME,
+ PARSER_RDATA_WF_BINARY }, true },
+ /* 31 */
+ { 31, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 32 */
+ { 32, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 33 */
+ { PARSER_RRTYPE_SRV, T_SRV, "SRV", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT,
+ PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_UNCOMPRESSED_DNAME },
+ true },
+ /* 34 */
+ { 34, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 35 */
+ { PARSER_RRTYPE_NAPTR, T_NAPTR, "NAPTR", 6,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 36 */
+ { PARSER_RRTYPE_KX, T_KX, "KX", 2,
+ { PARSER_RDATA_WF_SHORT,
+ PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 37 */
+ { PARSER_RRTYPE_CERT, T_CERT, "CERT", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true },
+ /* 38 */
+ { PARSER_RRTYPE_A6, T_A6, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 39 */
+ { PARSER_RRTYPE_DNAME, T_DNAME, "DNAME", 1,
+ { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 40 */
+ { 40, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 41 */
+ /* OPT has its parser token, but should never be in zone file... */
+ { PARSER_RRTYPE_OPT, T_OPT, "OPT", 1,
+ { PARSER_RDATA_WF_BINARY }, true },
+ /* 42 */
+ { PARSER_RRTYPE_APL, T_APL, "APL", PARSER_MAX_RDATA_ITEMS,
+ { PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL }, false },
+ /* 43 */
+ { PARSER_RRTYPE_DS, T_DS, "DS", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true },
+ /* 44 */
+ { PARSER_RRTYPE_SSHFP, T_SSHFP, "SSHFP", 3,
+ { PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BINARY }, true },
+ /* 45 */
+ { PARSER_RRTYPE_IPSECKEY, T_IPSECKEY, "IPSECKEY", 5,
+ { PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_IPSECGATEWAY,
+ PARSER_RDATA_WF_BINARY }, false },
+ /* 46 */
+ { PARSER_RRTYPE_RRSIG, T_RRSIG, "RRSIG", 9,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_LONG,
+ PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG,
+ PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BINARY,
+ PARSER_RDATA_WF_BINARY }, true },
+ /* 47 */
+ { PARSER_RRTYPE_NSEC, T_NSEC, "NSEC", 2,
+ { PARSER_RDATA_WF_BINARY, PARSER_RDATA_WF_BINARY }, true },
+ /* 48 */
+ { PARSER_RRTYPE_DNSKEY, T_DNSKEY, "DNSKEY", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true },
+ /* 49 */
+ { PARSER_RRTYPE_DHCID, T_DHCID, "DHCID", 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 50 */
+ { PARSER_RRTYPE_NSEC3, T_NSEC3, "NSEC3", 6,
+ { PARSER_RDATA_WF_BYTE, /* hash type */
+ PARSER_RDATA_WF_BYTE, /* flags */
+ PARSER_RDATA_WF_SHORT, /* iterations */
+ PARSER_RDATA_WF_BINARYWITHLENGTH, /* salt */
+ PARSER_RDATA_WF_BINARYWITHLENGTH, /* next hashed name */
+ PARSER_RDATA_WF_BINARY /* type bitmap */ }, true },
+ /* 51 */
+ { PARSER_RRTYPE_NSEC3PARAM, T_NSEC3PARAM, "NSEC3PARAM", 4,
+ { PARSER_RDATA_WF_BYTE, /* hash type */
+ PARSER_RDATA_WF_BYTE, /* flags */
+ PARSER_RDATA_WF_SHORT, /* iterations */
+ PARSER_RDATA_WF_BINARYWITHLENGTH /* salt */ }, true },
+ /* 52 */
+
+
+ /* In NSD they have indices between 52 and 99 filled with
+ unknown types. TODO add here if it's really needed? */
+ /* it is indeed needed, in rrtype_from_string */
+
+ /* There's a GNU extension that works like this: [first ... last] = value */
+
+ [53 ... 98] = { PARSER_RRTYPE_TYPEXXX, T_UTYPE, NULL, 1, { PARSER_RDATA_WF_BINARY }},
+
+ /* 99 */
+ [99] = { PARSER_RRTYPE_SPF, T_SPF, "SPF", PARSER_MAX_RDATA_ITEMS,
+ { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false },
+ [100 ... 32768] = { PARSER_RRTYPE_TYPEXXX, T_UTYPE, NULL, 1, { PARSER_RDATA_WF_BINARY }},
+ /* 32769 */
+ [32769] = { PARSER_RRTYPE_DLV, T_DLV, "DLV", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY } },
+};
+
+parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_type(uint16_t type)
+{
+ if (type <= PARSER_RRTYPE_DLV) {
+ return &knot_rrtype_descriptors[type];
+ }
+ return &knot_rrtype_descriptors[0];
+}
+
+/* I see a lot of potential here to speed up zone parsing - this is O(n) *
+ * could be better */
+parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_name(const char *name)
+{
+ if (!name) {
+ return NULL;
+ }
+
+ if (strcasecmp(name, "IN") == 0) {
+ return NULL;
+ }
+
+ if (isdigit((int)name[0])) {
+ return NULL;
+ }
+
+// /* The most common - A and NS. */
+// if (strcasecmp(name, "NS") == 0) {
+// return &knot_rrtype_descriptors[2];
+// }
+
+// if (strcasecmp(name, "A") == 0) {
+// return &knot_rrtype_descriptors[1];
+// }
+
+// /* Then RRSIG */
+// if (strcasecmp(name, "RRSIG") == 0) {
+// return &knot_rrtype_descriptors[46];
+// }
+
+// /* Then DS */
+// if (strcasecmp(name, "DS") == 0) {
+// return &knot_rrtype_descriptors[43];
+// }
+// /* Then NSEC3 */
+// if (strcasecmp(name, "NSEC3") == 0) {
+// return &knot_rrtype_descriptors[50];
+// }
+// /* Then NSEC */
+// if (strcasecmp(name, "NSEC") == 0) {
+// return &knot_rrtype_descriptors[47];
+// }
+
+ int i;
+
+ for (i = 0; i < PARSER_RRTYPE_LAST + 1; ++i) {
+ if (knot_rrtype_descriptors[i].name &&
+ strcasecmp(knot_rrtype_descriptors[i].name, name) == 0) {
+ return &knot_rrtype_descriptors[i];
+ }
+ }
+
+ if (knot_rrtype_descriptors[PARSER_RRTYPE_DLV].name &&
+ strcasecmp(knot_rrtype_descriptors[PARSER_RRTYPE_DLV].name,
+ name) == 0) {
+ return &knot_rrtype_descriptors[PARSER_RRTYPE_DLV];
+ }
+
+ return NULL;
+}
+
+const char *parser_rrtype_to_string(uint16_t rrtype)
+{
+ static char buf[20];
+ parser_rrtype_descriptor_t *descriptor =
+ parser_rrtype_descriptor_by_type(rrtype);
+ if (descriptor->name) {
+ return descriptor->name;
+ } else {
+ snprintf(buf, sizeof(buf), "TYPE%d", (int) rrtype);
+ return buf;
+ }
+}
+
+uint16_t parser_rrtype_from_string(const char *name)
+{
+ char *end;
+ long rrtype;
+ parser_rrtype_descriptor_t *entry;
+
+ entry = parser_rrtype_descriptor_by_name(name);
+ if (entry) {
+ return entry->type;
+ }
+
+ if (strlen(name) < 5) {
+ return 0;
+ }
+
+ if (strncasecmp(name, "TYPE", 4) != 0) {
+ return 0;
+ }
+
+ if (!isdigit((int)name[4])) {
+ return 0;
+ }
+
+ /* The rest from the string must be a number. */
+ rrtype = strtol(name + 4, &end, 10);
+ if (*end != '\0') {
+ return 0;
+ }
+ if (rrtype < 0 || rrtype > 65535L) {
+ return 0;
+ }
+
+ return (uint16_t) rrtype;
+}
+
+const char *parser_rrclass_to_string(uint16_t rrclass)
+{
+ static char buf[20];
+ knot_lookup_table_t *entry = knot_lookup_by_id(dns_rrclasses,
+ rrclass);
+ if (entry) {
+ assert(strlen(entry->name) < sizeof(buf));
+ knot_strlcpy(buf, entry->name, sizeof(buf));
+ } else {
+ snprintf(buf, sizeof(buf), "CLASS%d", (int) rrclass);
+ }
+ return buf;
+}
+
+uint16_t parser_rrclass_from_string(const char *name)
+{
+ char *end;
+ long rrclass;
+ knot_lookup_table_t *entry;
+
+ entry = knot_lookup_by_name(dns_rrclasses, name);
+ if (entry) {
+ return (uint16_t) entry->id;
+ }
+
+ if (strlen(name) < 6) {
+ return 0;
+ }
+
+ if (strncasecmp(name, "CLASS", 5) != 0) {
+ return 0;
+ }
+
+ if (!isdigit((int)name[5])) {
+ return 0;
+ }
+
+ // The rest from the string must be a number.
+ rrclass = strtol(name + 5, &end, 10);
+ if (*end != '\0') {
+ return 0;
+ }
+ if (rrclass < 0 || rrclass > 65535L) {
+ return 0;
+ }
+
+ return (uint16_t) rrclass;
+}
+
diff --git a/src/zcompile/parser-descriptor.h b/src/zcompile/parser-descriptor.h
new file mode 100644
index 0000000..c7865dd
--- /dev/null
+++ b/src/zcompile/parser-descriptor.h
@@ -0,0 +1,278 @@
+/*!
+ * \file parser-descriptor.h
+ *
+ * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * most of the work by NLnet Labs.
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief Contains resource record descriptor and its API
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KNOTD_PARSER_DESCRIPTOR_H_
+#define _KNOTD_PARSER_DESCRIPTOR_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libknot/util/utils.h"
+
+enum parser_mxrdtln {
+ PARSER_MAX_RDATA_ITEMS = 64,
+ PARSER_MAX_RDATA_ITEM_SIZE = 255,
+ PARSER_MAX_RDATA_WIRE_SIZE =
+ PARSER_MAX_RDATA_ITEMS * PARSER_MAX_RDATA_ITEM_SIZE
+};
+//#define MAXRDATALEN 64
+
+/* 64 is in NSD. Seems a little too much, but I'd say it's not a real issue. */
+
+/*!
+ * \brief Enum containing RR class codes.
+ */
+enum parser_rr_class {
+ PARSER_CLASS_IN = 1,
+ PARSER_CLASS_CS,
+ PARSER_CLASS_CH,
+ PARSER_CLASS_HS,
+ PARSER_CLASS_NONE = 254,
+ PARSER_CLASS_ANY = 255
+};
+
+typedef enum parser_rr_class parser_rr_class_t;
+
+enum parser_rr_type {
+ PARSER_RRTYPE_UNKNOWN, /*!< 0 - an unknown type */
+ PARSER_RRTYPE_A, /*!< 1 - a host address */
+ PARSER_RRTYPE_NS, /*!< 2 - an authoritative name server */
+ PARSER_RRTYPE_MD, /*!< 3 - a mail destination (Obsolete - use MX) */
+ PARSER_RRTYPE_MF, /*!< 4 - a mail forwarder (Obsolete - use MX) */
+ PARSER_RRTYPE_CNAME, /*!< 5 - the canonical name for an alias */
+ PARSER_RRTYPE_SOA, /*!< 6 - marks the start of a zone of authority */
+ PARSER_RRTYPE_MB, /*!< 7 - a mailbox domain name (EXPERIMENTAL) */
+ PARSER_RRTYPE_MG, /*!< 8 - a mail group member (EXPERIMENTAL) */
+ PARSER_RRTYPE_MR, /*!< 9 - a mail rename domain name (EXPERIMENTAL) */
+ PARSER_RRTYPE_NULL, /*!< 10 - a null RR (EXPERIMENTAL) */
+ PARSER_RRTYPE_WKS, /*!< 11 - a well known service description */
+ PARSER_RRTYPE_PTR, /*!< 12 - a domain name pointer */
+ PARSER_RRTYPE_HINFO, /*!< 13 - host information */
+ PARSER_RRTYPE_MINFO, /*!< 14 - mailbox or mail list information */
+ PARSER_RRTYPE_MX, /*!< 15 - mail exchange */
+ PARSER_RRTYPE_TXT, /*!< 16 - text strings */
+ PARSER_RRTYPE_RP, /*!< 17 - RFC1183 */
+ PARSER_RRTYPE_AFSDB, /*!< 18 - RFC1183 */
+ PARSER_RRTYPE_X25, /*!< 19 - RFC1183 */
+ PARSER_RRTYPE_ISDN, /*!< 20 - RFC1183 */
+ PARSER_RRTYPE_RT, /*!< 21 - RFC1183 */
+ PARSER_RRTYPE_NSAP, /*!< 22 - RFC1706 */
+
+ PARSER_RRTYPE_SIG = 24, /*!< 24 - 2535typecode */
+ PARSER_RRTYPE_KEY, /*!< 25 - 2535typecode */
+ PARSER_RRTYPE_PX, /*!< 26 - RFC2163 */
+
+ PARSER_RRTYPE_AAAA = 28, /*!< 28 - ipv6 address */
+ PARSER_RRTYPE_LOC, /*!< 29 - LOC record RFC1876 */
+ PARSER_RRTYPE_NXT, /*!< 30 - 2535typecode */
+
+ PARSER_RRTYPE_SRV = 33, /*!< 33 - SRV record RFC2782 */
+
+ PARSER_RRTYPE_NAPTR = 35, /*!< 35 - RFC2915 */
+ PARSER_RRTYPE_KX, /*!< 36 - RFC2230 Key Exchange Delegation Record */
+ PARSER_RRTYPE_CERT, /*!< 37 - RFC2538 */
+ PARSER_RRTYPE_A6, /*!< 38 - RFC2874 */
+ PARSER_RRTYPE_DNAME, /*!< 39 - RFC2672 */
+
+ PARSER_RRTYPE_OPT = 41, /*!< 41 - Pseudo OPT record... */
+ PARSER_RRTYPE_APL, /*!< 42 - RFC3123 */
+ PARSER_RRTYPE_DS, /*!< 43 - RFC 4033, 4034, and 4035 */
+ PARSER_RRTYPE_SSHFP, /*!< 44 - SSH Key Fingerprint */
+ PARSER_RRTYPE_IPSECKEY, /*!< 45 - public key for ipsec use. RFC 4025 */
+ PARSER_RRTYPE_RRSIG, /*!< 46 - RFC 4033, 4034, and 4035 */
+ PARSER_RRTYPE_NSEC, /*!< 47 - RFC 4033, 4034, and 4035 */
+ PARSER_RRTYPE_DNSKEY, /*!< 48 - RFC 4033, 4034, and 4035 */
+ PARSER_RRTYPE_DHCID, /*!< 49 - RFC4701 DHCP information */
+ /*!
+ * \brief 50 - NSEC3, secure denial, prevents zonewalking
+ */
+ PARSER_RRTYPE_NSEC3,
+ /*!
+ * \brief 51 - NSEC3PARAM at zone apex nsec3 parameters
+ */
+ PARSER_RRTYPE_NSEC3PARAM,
+
+ /* TODO consider some better way of doing this, indices too high */
+
+ PARSER_RRTYPE_SPF = 99, /*!< RFC 4408 */
+
+ // not designating any RRs
+ PARSER_RRTYPE_TSIG = 250,
+ PARSER_RRTYPE_IXFR = 251,
+ PARSER_RRTYPE_AXFR = 252,
+ /*!
+ * \brief A request for mailbox-related records (MB, MG or MR)
+ */
+ PARSER_RRTYPE_MAILB = 253,
+ /*!
+ * \brief A request for mail agent RRs (Obsolete - see MX)
+ */
+ PARSER_RRTYPE_MAILA = 254,
+ PARSER_RRTYPE_ANY = 255, /*!< any type (wildcard) */
+
+ // totally weird numbers (cannot use for indexing)
+ PARSER_RRTYPE_TA = 32768, /*!< DNSSEC Trust Authorities */
+ PARSER_RRTYPE_DLV = 32769, /*!< RFC 4431 */
+ PARSER_RRTYPE_TYPEXXX = 32770
+};
+
+/*!
+ * \brief Enum containing RR type codes.
+ *
+ * \todo Not all indices can be used for indexing.
+ */
+typedef enum parser_rr_type parser_rr_type_t;
+
+static uint const PARSER_RRTYPE_LAST = PARSER_RRTYPE_NSEC3PARAM;
+
+enum parser_rdata_wireformat {
+ /*!
+ * \brief Possibly compressed domain name.
+ */
+ PARSER_RDATA_WF_COMPRESSED_DNAME = 50,
+ PARSER_RDATA_WF_UNCOMPRESSED_DNAME = 51, /*!< Uncompressed domain name. */
+ PARSER_RDATA_WF_LITERAL_DNAME = 52, /*!< Literal (not downcased) dname. */
+ PARSER_RDATA_WF_BYTE = 1, /*!< 8-bit integer. */
+ PARSER_RDATA_WF_SHORT = 2, /*!< 16-bit integer. */
+ PARSER_RDATA_WF_LONG = 4, /*!< 32-bit integer. */
+ PARSER_RDATA_WF_TEXT = 53, /*!< Text string. */
+ PARSER_RDATA_WF_A = 58, /*!< 32-bit IPv4 address. */
+ PARSER_RDATA_WF_AAAA = 16, /*!< 128-bit IPv6 address. */
+ PARSER_RDATA_WF_BINARY = 54, /*!< Binary data (unknown length). */
+ /*!
+ * \brief Binary data preceded by 1 byte length
+ */
+ PARSER_RDATA_WF_BINARYWITHLENGTH = 55,
+ PARSER_RDATA_WF_APL = 56, /*!< APL data. */
+ PARSER_RDATA_WF_IPSECGATEWAY = 57 /*!< IPSECKEY gateway ip4, ip6 or dname. */
+};
+
+/*!
+ * \brief Enum containing wireformat codes. Taken from NSD's "dns.h"
+ */
+typedef enum parser_rdatawireformat parser_rdata_wireformat_t;
+
+struct parser_rrtype_descriptor {
+ uint16_t type; /*!< RR type */
+ int token; /*< Token used in zoneparser */
+ const char *name; /*!< Textual name. */
+ uint8_t length; /*!< Maximum number of RDATA items. */
+ /*!
+ * \brief rdata_wireformat_type
+ */
+ uint8_t wireformat[PARSER_MAX_RDATA_ITEMS];
+ bool fixed_items; /*!< Has fixed number of RDATA items? */
+};
+
+/*!
+ * \brief Structure holding RR descriptor
+ */
+typedef struct parser_rrtype_descriptor parser_rrtype_descriptor_t;
+
+/*!
+ * \brief Gets RR descriptor for given RR type.
+ *
+ * \param type Code of RR type whose descriptor should be returned.
+ *
+ * \return RR descriptor for given type code, NULL descriptor if
+ * unknown type.
+ *
+ * \todo Change return value to const.
+ */
+parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_type(uint16_t type);
+
+/*!
+ * \brief Gets RR descriptor for given RR name.
+ *
+ * \param name Mnemonic of RR type whose descriptor should be returned.
+ *
+ * \return RR descriptor for given name, NULL descriptor if
+ * unknown type.
+ *
+ * \todo Change return value to const.
+ */
+parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_name(const char *name);
+
+/*!
+ * \brief Converts numeric type representation to mnemonic string.
+ *
+ * \param rrtype Type RR type code to be converted.
+ *
+ * \return Mnemonic string if found, str(TYPE[rrtype]) otherwise.
+ */
+const char *parser_rrtype_to_string(uint16_t rrtype);
+
+/*!
+ * \brief Converts mnemonic string representation of a type to numeric one.
+ *
+ * \param name Mnemonic string to be converted.
+ *
+ * \return Correct code if found, 0 otherwise.
+ */
+uint16_t parser_rrtype_from_string(const char *name);
+
+/*!
+ * \brief Converts numeric class representation to string one.
+ *
+ * \param rrclass Class code to be converted.
+ *
+ * \return String represenation of class if found,
+ * str(CLASS[rrclass]) otherwise.
+ */
+const char *parser_rrclass_to_string(uint16_t rrclass);
+
+/*!
+ * \brief Converts string representation of a class to numeric one.
+ *
+ * \param name Class string to be converted.
+ *
+ * \return Correct code if found, 0 otherwise.
+ */
+uint16_t parser_rrclass_from_string(const char *name);
+
+#endif /* _KNOTD_PARSER_DESCRIPTOR_H_ */
+
+/*! @} */
diff --git a/src/zcompile/parser-util.c b/src/zcompile/parser-util.c
new file mode 100644
index 0000000..e7733ef
--- /dev/null
+++ b/src/zcompile/parser-util.c
@@ -0,0 +1,2435 @@
+/*!
+ * \file parser-util.c
+ *
+ * \author NLnet Labs
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief utility functions for zone parser.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+//#include "common.h"
+#include "common/base32hex.h"
+#include "zcompile/parser-util.h"
+#include "zcompile/zcompile.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/util/utils.h"
+#include "zcompile/zcompile-error.h"
+
+#define IP6ADDRLEN (128/8)
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+#define APL_NEGATION_MASK 0x80U
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int inet_pton(int af, const char *src, void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+//int my_b32_pton(const char *src, uint8_t *target, size_t tsize)
+//{
+// char ch;
+// size_t p = 0;
+
+// memset(target, '\0', tsize);
+// while ((ch = *src++)) {
+// uint8_t d;
+// size_t b;
+// size_t n;
+
+// if (p + 5 >= tsize * 8) {
+// return -1;
+// }
+
+// if (isspace(ch)) {
+// continue;
+// }
+
+// if (ch >= '0' && ch <= '9') {
+// d = ch - '0';
+// } else if (ch >= 'A' && ch <= 'V') {
+// d = ch - 'A' + 10;
+// } else if (ch >= 'a' && ch <= 'v') {
+// d = ch - 'a' + 10;
+// } else {
+// return -1;
+// }
+
+// b = 7 - p % 8;
+// n = p / 8;
+
+// if (b >= 4) {
+// target[n] |= d << (b - 4);
+// } else {
+// target[n] |= d >> (4 - b);
+// target[n+1] |= d << (b + 4);
+// }
+// p += 5;
+// }
+// return (p + 7) / 8;
+//}
+
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+int inet_pton4(const char *src, uint8_t *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ uint8_t tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ uint32_t new = *tp * 10 + (pch - digits);
+
+ if (new > 255) {
+ return (0);
+ }
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4) {
+ return (0);
+ }
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4) {
+ return (0);
+ }
+ *++tp = 0;
+ saw_digit = 0;
+ } else {
+ return (0);
+ }
+ }
+ if (octets < 4) {
+ return (0);
+ }
+
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+int inet_pton6(const char *src, uint8_t *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ uint32_t val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':') {
+ return (0);
+ }
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) {
+ pch = strchr((xdigits = xdigits_u), ch);
+ }
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff) {
+ return (0);
+ }
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp) {
+ return (0);
+ }
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp) {
+ return (0);
+ }
+ *tp++ = (uint8_t)(val >> 8) & 0xff;
+ *tp++ = (uint8_t) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp) {
+ return (0);
+ }
+ *tp++ = (uint8_t)(val >> 8) & 0xff;
+ *tp++ = (uint8_t) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp) {
+ return (0);
+ }
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+
+
+#ifndef IN6ADDRSZ
+#define IN6ADDRSZ 16 /* IPv6 T_AAAA */
+#endif
+
+#ifndef INT16SZ
+#define INT16SZ 2 /* for systems without 16-bit ints */
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+//const char *inet_ntop(int af, const void *src, char *dst, size_t size)
+//{
+// switch (af) {
+// case AF_INET:
+// return (inet_ntop4(src, dst, size));
+// case AF_INET6:
+// return (inet_ntop6(src, dst, size));
+// default:
+// errno = EAFNOSUPPORT;
+// return (NULL);
+// }
+// /* NOTREACHED */
+//}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address, more or less like inet_ntoa()
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a u_char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *inet_ntop4(const u_char *src, char *dst, size_t size)
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+ int l;
+
+ l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]);
+ if (l <= 0 || l >= (int)size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ knot_strlcpy(dst, tmp, size);
+ return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *inet_ntop6(const u_char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+ char *tp, *ep;
+ struct {
+ int base, len;
+ } best, cur;
+ best.base = cur.base =-1;
+ best.len = cur.len = 0;
+ u_int words[IN6ADDRSZ / INT16SZ];
+ int i;
+ int advance;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < IN6ADDRSZ; i++) {
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ }
+
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1) {
+ cur.base = i, cur.len = 1;
+ } else {
+ cur.len++;
+ }
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len) {
+ best = cur;
+ }
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len) {
+ best = cur;
+ }
+ }
+ if (best.base != -1 && best.len < 2) {
+ best.base = -1;
+ }
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ ep = tmp + sizeof(tmp);
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base) {
+ if (tp + 1 >= ep) {
+ return (NULL);
+ }
+ *tp++ = ':';
+ }
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0) {
+ if (tp + 1 >= ep) {
+ return (NULL);
+ }
+ *tp++ = ':';
+ }
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src + 12, tp, (size_t)(ep - tp))) {
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ advance = snprintf(tp, ep - tp, "%x", words[i]);
+ if (advance <= 0 || advance >= ep - tp) {
+ return (NULL);
+ }
+ tp += advance;
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (IN6ADDRSZ / INT16SZ)) {
+ if (tp + 1 >= ep) {
+ return (NULL);
+ }
+ *tp++ = ':';
+ }
+ if (tp + 1 >= ep) {
+ return (NULL);
+ }
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ knot_strlcpy(dst, tmp, size);
+ return (dst);
+}
+
+
+static int b64rmap_initialized = 0;
+static uint8_t b64rmap[256];
+
+static const uint8_t b64rmap_special = 0xf0;
+static const uint8_t b64rmap_end = 0xfd;
+static const uint8_t b64rmap_space = 0xfe;
+static const uint8_t b64rmap_invalid = 0xff;
+
+/**
+ * Initializing the reverse map is not thread safe.
+ * Which is fine for NSD. For now...
+ **/
+void b64_initialize_rmap()
+{
+ int i;
+ char ch;
+
+ /* Null: end of string, stop parsing */
+ b64rmap[0] = b64rmap_end;
+
+ for (i = 1; i < 256; ++i) {
+ ch = (char)i;
+ /* Whitespaces */
+ if (isspace(ch)) {
+ b64rmap[i] = b64rmap_space;
+ }
+ /* Padding: stop parsing */
+ else if (ch == Pad64) {
+ b64rmap[i] = b64rmap_end;
+ }
+ /* Non-base64 char */
+ else {
+ b64rmap[i] = b64rmap_invalid;
+ }
+ }
+
+ /* Fill reverse mapping for base64 chars */
+ for (i = 0; Base64[i] != '\0'; ++i) {
+ b64rmap[(uint8_t)Base64[i]] = i;
+ }
+
+ b64rmap_initialized = 1;
+}
+
+int b64_pton_do(char const *src, uint8_t *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ uint8_t ofs;
+
+ state = 0;
+ tarindex = 0;
+
+ while (1) {
+ ch = *src++;
+ ofs = b64rmap[ch];
+
+ if (ofs >= b64rmap_special) {
+ /* Ignore whitespaces */
+ if (ofs == b64rmap_space) {
+ continue;
+ }
+ /* End of base64 characters */
+ if (ofs == b64rmap_end) {
+ break;
+ }
+ /* A non-base64 character. */
+ return (-1);
+ }
+
+ switch (state) {
+ case 0:
+ if ((size_t)tarindex >= targsize) {
+ return (-1);
+ }
+ target[tarindex] = ofs << 2;
+ state = 1;
+ break;
+ case 1:
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs >> 4;
+ target[tarindex+1] = (ofs & 0x0f)
+ << 4 ;
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs >> 2;
+ target[tarindex+1] = (ofs & 0x03)
+ << 6;
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if ((size_t)tarindex >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs;
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ break;
+ }
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64) {
+ return (-1);
+ }
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ return (-1);
+ }
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target[tarindex] != 0) {
+ return (-1);
+ }
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0) {
+ return (-1);
+ }
+ }
+
+ return (tarindex);
+}
+
+
+int b64_pton_len(char const *src)
+{
+ int tarindex, state, ch;
+ uint8_t ofs;
+
+ state = 0;
+ tarindex = 0;
+
+ while (1) {
+ ch = *src++;
+ ofs = b64rmap[ch];
+
+ if (ofs >= b64rmap_special) {
+ /* Ignore whitespaces */
+ if (ofs == b64rmap_space) {
+ continue;
+ }
+ /* End of base64 characters */
+ if (ofs == b64rmap_end) {
+ break;
+ }
+ /* A non-base64 character. */
+ return (-1);
+ }
+
+ switch (state) {
+ case 0:
+ state = 1;
+ break;
+ case 1:
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ break;
+ }
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64) {
+ return (-1);
+ }
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ return (-1);
+ }
+
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0) {
+ return (-1);
+ }
+ }
+
+ return (tarindex);
+}
+
+int b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+ if (!b64rmap_initialized) {
+ b64_initialize_rmap();
+ }
+
+ if (target) {
+ return b64_pton_do(src, target, targsize);
+ } else {
+ return b64_pton_len(src);
+ }
+}
+
+void set_bit(uint8_t bits[], size_t index)
+{
+ /*
+ * The bits are counted from left to right, so bit #0 is the
+ * left most bit.
+ */
+ bits[index / 8] |= (1 << (7 - index % 8));
+}
+
+uint32_t strtoserial(const char *nptr, const char **endptr)
+{
+ uint32_t i = 0;
+ uint32_t serial = 0;
+
+ for (*endptr = nptr; **endptr; (*endptr)++) {
+ switch (**endptr) {
+ case ' ':
+ case '\t':
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i *= 10;
+ i += (**endptr - '0');
+ break;
+ default:
+ break;
+ }
+ }
+ serial += i;
+ return serial;
+}
+
+inline void write_uint32(void *dst, uint32_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ *(uint32_t *) dst = htonl(data);
+#else
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t)((data >> 24) & 0xff);
+ p[1] = (uint8_t)((data >> 16) & 0xff);
+ p[2] = (uint8_t)((data >> 8) & 0xff);
+ p[3] = (uint8_t)(data & 0xff);
+#endif
+}
+
+uint32_t strtottl(const char *nptr, const char **endptr)
+{
+ uint32_t i = 0;
+ uint32_t seconds = 0;
+
+ for (*endptr = nptr; **endptr; (*endptr)++) {
+ switch (**endptr) {
+ case ' ':
+ case '\t':
+ break;
+ case 's':
+ case 'S':
+ seconds += i;
+ i = 0;
+ break;
+ case 'm':
+ case 'M':
+ seconds += i * 60;
+ i = 0;
+ break;
+ case 'h':
+ case 'H':
+ seconds += i * 60 * 60;
+ i = 0;
+ break;
+ case 'd':
+ case 'D':
+ seconds += i * 60 * 60 * 24;
+ i = 0;
+ break;
+ case 'w':
+ case 'W':
+ seconds += i * 60 * 60 * 24 * 7;
+ i = 0;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i *= 10;
+ i += (**endptr - '0');
+ break;
+ default:
+ seconds += i;
+ return seconds;
+ }
+ }
+ seconds += i;
+ return seconds;
+}
+
+/* Number of days per month (except for February in leap years). */
+static const int mdays[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static int is_leap_year(int year)
+{
+ return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
+}
+
+static int leap_days(int y1, int y2)
+{
+ --y1;
+ --y2;
+ return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400);
+}
+
+/*
+ * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
+ */
+time_t mktime_from_utc(const struct tm *tm)
+{
+ int year = 1900 + tm->tm_year;
+ time_t days = 365 * (year - 1970) + leap_days(1970, year);
+ time_t hours;
+ time_t minutes;
+ time_t seconds;
+ int i;
+
+ for (i = 0; i < tm->tm_mon; ++i) {
+ days += mdays[i];
+ }
+ if (tm->tm_mon > 1 && is_leap_year(year)) {
+ ++days;
+ }
+ days += tm->tm_mday - 1;
+
+ hours = days * 24 + tm->tm_hour;
+ minutes = hours * 60 + tm->tm_min;
+ seconds = minutes * 60 + tm->tm_sec;
+
+ return seconds;
+}
+
+/*!< Following functions are conversions from text to wire. */
+
+//#define DEBUG_UNKNOWN_RDATA
+
+#ifdef DEBUG_UNKNOWN_RDATA
+#define dbg_rdata(msg...) fprintf(stderr, msg)
+#define DBG_RDATA(cmds) do { cmds } while (0)
+#else
+#define dbg_rdata(msg...)
+#define DBG_RDATA(cmds)
+#endif
+
+
+
+#define IP6ADDRLEN (128/8)
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+#define APL_NEGATION_MASK 0x80U
+#define APL_LENGTH_MASK (~APL_NEGATION_MASK)
+
+//#define ZP_DEBUG
+
+#ifdef ZP_DEBUG
+#define dbg_zp(msg...) fprintf(stderr, msg)
+#else
+#define dbg_zp(msg...)
+#endif
+
+
+/*!
+ * \brief Return data of raw data item.
+ *
+ * \param item Item.
+ * \return uint16_t * Raw data.
+ */
+static inline uint16_t * rdata_atom_data(knot_rdata_item_t item)
+{
+ return (uint16_t *)(item.raw_data + 1);
+}
+
+/*!
+ * \brief Return type of RRSet covered by given RRSIG.
+ *
+ * \param rrset RRSIG.
+ * \return uint16_t Type covered.
+ */
+uint16_t rrsig_type_covered(knot_rrset_t *rrset)
+{
+ assert(rrset->rdata->items[0].raw_data[0] == sizeof(uint16_t));
+
+ return ntohs(*(uint16_t *) rdata_atom_data(rrset->rdata->items[0]));
+}
+
+/*!
+ * \brief Checks if item contains domain.
+ *
+ * \param type Type of RRSet.
+ * \param index Index to check.
+ *
+ * \return > 1 if item is domain, 0 otherwise.
+ */
+static inline int rdata_atom_is_domain(uint16_t type, size_t index)
+{
+ const knot_rrtype_descriptor_t *descriptor
+ = knot_rrtype_descriptor_by_type(type);
+ return (index < descriptor->length
+ && (descriptor->wireformat[index] ==
+ KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ descriptor->wireformat[index] ==
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME));
+}
+
+/*!
+ * \brief Returns which wireformat type is on given index.
+ *
+ * \param type Type of RRSet.
+ * \param index Index.
+ *
+ * \return uint8_t Wireformat type.
+ */
+static inline uint8_t rdata_atom_wireformat_type(uint16_t type, size_t index)
+{
+ const knot_rrtype_descriptor_t *descriptor =
+ knot_rrtype_descriptor_by_type(type);
+ assert(index < descriptor->length);
+ return descriptor->wireformat[index];
+}
+
+/*!
+ * \brief Converts rdata wireformat to rdata items.
+ *
+ * \param wireformat Wireformat/.
+ * \param rrtype RR type.
+ * \param data_size Size of wireformat.
+ * \param items created rdata items.
+ *
+ * \return Number of items converted.
+ */
+static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat,
+ uint16_t rrtype,
+ const uint16_t data_size,
+ knot_rdata_item_t **items)
+{
+ dbg_rdata("read length: %d\n", data_size);
+ uint16_t const *end = (uint16_t *)((uint8_t *)wireformat + (data_size));
+ dbg_rdata("set end pointer: %p which means length: %d\n", end,
+ (uint8_t *)end - (uint8_t *)wireformat);
+ size_t i;
+ knot_rdata_item_t *temp_rdatas =
+ malloc(sizeof(*temp_rdatas) * MAXRDATALEN);
+ if (temp_rdatas == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+ memset(temp_rdatas, 0, sizeof(*temp_rdatas) * MAXRDATALEN);
+
+ knot_rrtype_descriptor_t *descriptor =
+ knot_rrtype_descriptor_by_type(rrtype);
+
+ assert(descriptor->length <= MAXRDATALEN);
+
+ dbg_rdata("will be parsing %d items, total size: %d\n",
+ descriptor->length, data_size);
+
+ for (i = 0; i < descriptor->length; ++i) {
+ int is_domain = 0;
+ int is_wirestore = 0;
+ size_t length = 0;
+ length = 0;
+ int required = descriptor->length;
+
+ switch (rdata_atom_wireformat_type(rrtype, i)) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ is_domain = 1;
+ break;
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ is_domain = 1;
+ is_wirestore = 1;
+ break;
+ case KNOT_RDATA_WF_BYTE:
+ length = sizeof(uint8_t);
+ break;
+ case KNOT_RDATA_WF_SHORT:
+ length = sizeof(uint16_t);
+ break;
+ case KNOT_RDATA_WF_LONG:
+ length = sizeof(uint32_t);
+ break;
+ case KNOT_RDATA_WF_TEXT:
+ case KNOT_RDATA_WF_BINARYWITHLENGTH:
+ /* Length is stored in the first byte. */
+ length = 1;
+ if ((uint8_t *)wireformat + length <= (uint8_t *)end) {
+ // length += wireformat[length - 1];
+ length += *((uint8_t *)wireformat);
+ dbg_rdata("%d: set new length: %d\n", i,
+ length);
+ }
+ /*if (buffer_position(packet) + length <= end) {
+ length += buffer_current(packet)[length - 1];
+ }*/
+ break;
+ case KNOT_RDATA_WF_A:
+ length = sizeof(in_addr_t);
+ break;
+ case KNOT_RDATA_WF_AAAA:
+ length = IP6ADDRLEN;
+ break;
+ case KNOT_RDATA_WF_BINARY:
+ /* Remaining RDATA is binary. */
+ dbg_rdata("%d: guessing length from pointers: %p %p\n",
+ i,
+ wireformat, end);
+ length = (uint8_t *)end - (uint8_t *)wireformat;
+// length = end - buffer_position(packet);
+ break;
+ case KNOT_RDATA_WF_APL:
+ length = (sizeof(uint16_t) /* address family */
+ + sizeof(uint8_t) /* prefix */
+ + sizeof(uint8_t)); /* length */
+ if ((uint8_t *)wireformat + length <= (uint8_t *)end) {
+ /* Mask out negation bit. */
+ length += (wireformat[length - 1]
+ & APL_LENGTH_MASK);
+ }
+ break;
+ case KNOT_RDATA_WF_IPSECGATEWAY:
+ switch (rdata_atom_data(temp_rdatas[1])[0]) {
+ /* gateway type */
+ default:
+ case IPSECKEY_NOGATEWAY:
+ length = 0;
+ break;
+ case IPSECKEY_IP4:
+ length = 4;
+ break;
+ case IPSECKEY_IP6:
+ length = IP6ADDRLEN;
+ break;
+ case IPSECKEY_DNAME:
+ is_domain = 1;
+ is_wirestore = 1;
+ break;
+ }
+ break;
+ }
+
+ if (is_domain) {
+ knot_dname_t *dname;
+
+ if (!required && (wireformat == end)) {
+ break;
+ }
+
+ dname = knot_dname_new_from_str((char *)wireformat,
+ length,
+ NULL);
+
+ if (dname == NULL) {
+ dbg_rdata("malformed dname!\n");
+ /*! \todo rdata purge */
+ free(temp_rdatas);
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+ dbg_rdata("%d: created dname: %s\n", i,
+ knot_dname_to_str(dname));
+
+ if (is_wirestore) {
+ /*temp_rdatas[i].raw_data =
+ (uint16_t *) region_alloc(
+ region, sizeof(uint16_t) + dname->name_size);
+ temp_rdatas[i].data[0] = dname->name_size;
+ memcpy(temp_rdatas[i].data+1, dname_name(dname),
+ dname->name_size); */
+ temp_rdatas[i].raw_data =
+ malloc(sizeof(uint16_t) +
+ sizeof(uint8_t) * dname->size);
+ if (temp_rdatas[i].raw_data == NULL) {
+ ERR_ALLOC_FAILED;
+ /*! \todo rdata purge */
+ free(temp_rdatas);
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ temp_rdatas[i].raw_data[0] = dname->size;
+ memcpy(temp_rdatas[i].raw_data + 1,
+ dname->name, dname->size);
+
+ knot_dname_release(dname);
+ } else {
+ temp_rdatas[i].dname = dname;
+ }
+
+ } else {
+ dbg_rdata("%d :length: %d %d %p %p\n", i, length,
+ end - wireformat,
+ wireformat, end);
+ if ((uint8_t *)wireformat + length > (uint8_t *)end) {
+ if (required) {
+ /* Truncated RDATA. */
+ /*! \todo rdata purge */
+ free(temp_rdatas);
+ dbg_rdata("truncated rdata\n");
+ return KNOTDZCOMPILE_EBRDATA;
+ } else {
+ break;
+ }
+ }
+
+ assert(wireformat <= end); /*!< \todo remove! */
+ dbg_rdata("calling init with: %p and length : %d\n",
+ wireformat, length);
+ temp_rdatas[i].raw_data = alloc_rdata_init(wireformat,
+ length);
+ if (temp_rdatas[i].raw_data == NULL) {
+ ERR_ALLOC_FAILED;
+ /*! \todo rdata purge */
+ free(temp_rdatas);
+ return -1;
+ }
+
+// temp_rdatas[i].raw_data[0] = length;
+// memcpy(temp_rdatas[i].raw_data + 1, wireformat, length);
+
+/* temp_rdatas[i].data = (uint16_t *) region_alloc(
+ region, sizeof(uint16_t) + length);
+ temp_rdatas[i].data[0] = length;
+ buffer_read(packet,
+ temp_rdatas[i].data + 1, length); */
+ }
+ dbg_rdata("%d: adding length: %d (remaining: %d)\n", i, length,
+ (uint8_t *)end - ((uint8_t *)wireformat + length));
+// hex_print(temp_rdatas[i].raw_data + 1, length);
+ wireformat = (uint16_t *)((uint8_t *)wireformat + length);
+// wireformat = wireformat + length;
+ dbg_rdata("wire: %p\n", wireformat);
+ dbg_rdata("remaining now: %d\n",
+ end - wireformat);
+
+ }
+
+ dbg_rdata("%p %p\n", wireformat, (uint8_t *)wireformat);
+
+ if (wireformat < end) {
+ /* Trailing garbage. */
+ dbg_rdata("w: %p e: %p %d\n", wireformat, end, end - wireformat);
+// region_destroy(temp_region);
+ free(temp_rdatas);
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+
+ *items = temp_rdatas;
+ /* *rdatas = (rdata_atom_type *) region_alloc_init(
+ region, temp_rdatas, i * sizeof(rdata_atom_type)); */
+ return (ssize_t)i;
+}
+
+/* Taken from RFC 2535, section 7. */
+knot_lookup_table_t dns_algorithms[] = {
+ { 1, "RSAMD5" }, /* RFC 2537 */
+ { 2, "DH" }, /* RFC 2539 */
+ { 3, "DSA" }, /* RFC 2536 */
+ { 4, "ECC" },
+ { 5, "RSASHA1" }, /* RFC 3110 */
+ { 252, "INDIRECT" },
+ { 253, "PRIVATEDNS" },
+ { 254, "PRIVATEOID" },
+ { 0, NULL }
+};
+
+/* Taken from RFC 4398, section 2.1. */
+knot_lookup_table_t dns_certificate_types[] = {
+ /* 0 Reserved */
+ { 1, "PKIX" }, /* X.509 as per PKIX */
+ { 2, "SPKI" }, /* SPKI cert */
+ { 3, "PGP" }, /* OpenPGP packet */
+ { 4, "IPKIX" }, /* The URL of an X.509 data object */
+ { 5, "ISPKI" }, /* The URL of an SPKI certificate */
+ { 6, "IPGP" }, /* The fingerprint and URL of an OpenPGP packet */
+ { 7, "ACPKIX" }, /* Attribute Certificate */
+ { 8, "IACPKIX" }, /* The URL of an Attribute Certificate */
+ { 253, "URI" }, /* URI private */
+ { 254, "OID" }, /* OID private */
+ /* 255 Reserved */
+ /* 256-65279 Available for IANA assignment */
+ /* 65280-65534 Experimental */
+ /* 65535 Reserved */
+ { 0, NULL }
+};
+
+/* Imported from lexer. */
+extern int hexdigit_to_int(char ch);
+
+extern uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE];
+extern uint16_t nsec_highest_rcode;
+
+/*!
+ * \brief Allocate SIZE+sizeof(uint16_t) bytes and store SIZE in the first
+ * element. Return a pointer to the allocation.
+ *
+ * \param size How many bytes to allocate.
+ */
+static uint16_t * alloc_rdata(size_t size)
+{
+ uint16_t *result = malloc(sizeof(uint16_t) + size);
+ *result = size;
+ return result;
+}
+
+uint16_t *alloc_rdata_init(const void *data, size_t size)
+{
+ uint16_t *result = malloc(sizeof(uint16_t) + size);
+ if (result == NULL) {
+ return NULL;
+ }
+ *result = size;
+ memcpy(result + 1, data, size);
+ return result;
+}
+
+/*
+ * These are parser function for generic zone file stuff.
+ */
+uint16_t * zparser_conv_hex(const char *hex, size_t len)
+{
+ /* convert a hex value to wireformat */
+ uint16_t *r = NULL;
+ uint8_t *t;
+ int i;
+
+ if (len % 2 != 0) {
+ zc_error_prev_line("number of hex digits "
+ "must be a multiple of 2");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else if (len > MAX_RDLENGTH * 2) {
+ zc_error_prev_line("hex data exceeds maximum rdata length (%d)",
+ MAX_RDLENGTH);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ /* the length part */
+
+ r = alloc_rdata(len / 2);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ t = (uint8_t *)(r + 1);
+
+ /* Now process octet by octet... */
+ while (*hex) {
+ *t = 0;
+ for (i = 16; i >= 1; i -= 15) {
+ if (isxdigit((int)*hex)) {
+ *t += hexdigit_to_int(*hex) * i;
+ } else {
+ zc_error_prev_line(
+ "illegal hex character '%c'",
+ (int) *hex);
+ parser->error_occurred =
+ KNOTDZCOMPILE_EBRDATA;
+ free(r);
+ return NULL;
+ }
+ ++hex;
+ }
+ ++t;
+ }
+ }
+
+ return r;
+}
+
+/* convert hex, precede by a 1-byte length */
+uint16_t * zparser_conv_hex_length(const char *hex, size_t len)
+{
+ uint16_t *r = NULL;
+ uint8_t *t;
+ int i;
+ if (len % 2 != 0) {
+ zc_error_prev_line("number of hex digits must be a "
+ "multiple of 2");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else if (len > 255 * 2) {
+ zc_error_prev_line("hex data exceeds 255 bytes");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ uint8_t *l;
+
+ /* the length part */
+ r = alloc_rdata(len / 2 + 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ t = (uint8_t *)(r + 1);
+
+ l = t++;
+ *l = '\0';
+
+ /* Now process octet by octet... */
+ while (*hex) {
+ *t = 0;
+ for (i = 16; i >= 1; i -= 15) {
+ if (isxdigit((int)*hex)) {
+ *t += hexdigit_to_int(*hex) * i;
+ } else {
+ zc_error_prev_line(
+ "illegal hex character '%c'",
+ (int) *hex);
+ parser->error_occurred =
+ KNOTDZCOMPILE_EBRDATA;
+ free(r);
+ return NULL;
+ }
+ ++hex;
+ }
+ ++t;
+ ++*l;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_time(const char *time)
+{
+ /* convert a time YYHM to wireformat */
+ uint16_t *r = NULL;
+ struct tm tm;
+
+ /* Try to scan the time... */
+ if (!strptime(time, "%Y%m%d%H%M%S", &tm)) {
+ zc_error_prev_line("date and time is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ uint32_t l = htonl(mktime_from_utc(&tm));
+ r = alloc_rdata_init(&l, sizeof(l));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_services(const char *protostr, char *servicestr)
+{
+ /*
+ * Convert a protocol and a list of service port numbers
+ * (separated by spaces) in the rdata to wireformat
+ */
+ uint16_t *r = NULL;
+ uint8_t *p;
+ uint8_t bitmap[65536/8];
+ char sep[] = " ";
+ char *word;
+ int max_port = -8;
+ /* convert a protocol in the rdata to wireformat */
+ struct protoent *proto;
+
+ memset(bitmap, 0, sizeof(bitmap));
+
+ proto = getprotobyname(protostr);
+ if (!proto) {
+ proto = getprotobynumber(atoi(protostr));
+ }
+ if (!proto) {
+ zc_error_prev_line("unknown protocol '%s'", protostr);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ return NULL;
+ }
+
+ char *sp = 0;
+ while ((word = strtok_r(servicestr, sep, &sp))) {
+ struct servent *service;
+ int port;
+
+ service = getservbyname(word, proto->p_name);
+ if (service) {
+ /* Note: ntohs not ntohl! Strange but true. */
+ port = ntohs((uint16_t) service->s_port);
+ } else {
+ char *end;
+ port = strtol(word, &end, 10);
+ if (*end != '\0') {
+ zc_error_prev_line(
+ "unknown service '%s' for"
+ " protocol '%s'",
+ word, protostr);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ continue;
+ }
+ }
+
+ if (port < 0 || port > 65535) {
+ zc_error_prev_line("bad port number %d", port);
+ } else {
+ set_bit(bitmap, port);
+ if (port > max_port) {
+ max_port = port;
+ }
+ }
+ }
+
+ r = alloc_rdata(sizeof(uint8_t) + max_port / 8 + 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ p = (uint8_t *)(r + 1);
+ *p = proto->p_proto;
+ memcpy(p + 1, bitmap, *r);
+
+ return r;
+}
+
+uint16_t * zparser_conv_serial(const char *serialstr)
+{
+ uint16_t *r = NULL;
+ uint32_t serial;
+ const char *t;
+
+ serial = strtoserial(serialstr, &t);
+ if (*t != '\0') {
+ zc_error_prev_line("serial is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ serial = htonl(serial);
+ r = alloc_rdata_init(&serial, sizeof(serial));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_period(const char *periodstr)
+{
+ /* convert a time period (think TTL's) to wireformat) */
+ uint16_t *r = NULL;
+ uint32_t period;
+ const char *end;
+
+ /* Allocate required space... */
+ period = strtottl(periodstr, &end);
+ if (*end != '\0') {
+ zc_error_prev_line("time period is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ period = htonl(period);
+ r = alloc_rdata_init(&period, sizeof(period));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_short(const char *text)
+{
+ uint16_t *r = NULL;
+ uint16_t value;
+ char *end;
+
+ value = htons((uint16_t) strtol(text, &end, 10));
+ if (*end != '\0') {
+ zc_error_prev_line("integer value is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(&value, sizeof(value));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_byte(const char *text)
+{
+ uint16_t *r = NULL;
+ uint8_t value;
+ char *end;
+
+ value = (uint8_t) strtol(text, &end, 10);
+ if (*end != '\0') {
+ zc_error_prev_line("integer value is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(&value, sizeof(value));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_algorithm(const char *text)
+{
+ const knot_lookup_table_t *alg;
+ uint8_t id;
+
+ alg = knot_lookup_by_name(dns_algorithms, text);
+ if (alg) {
+ id = (uint8_t) alg->id;
+ } else {
+ char *end;
+ id = (uint8_t) strtol(text, &end, 10);
+ if (*end != '\0') {
+ zc_error_prev_line("algorithm is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ return NULL;
+ }
+ }
+
+ uint16_t *r = alloc_rdata_init(&id, sizeof(id));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ return r;
+}
+
+uint16_t * zparser_conv_certificate_type(const char *text)
+{
+ /* convert a algoritm string to integer */
+ const knot_lookup_table_t *type;
+ uint16_t id;
+
+ type = knot_lookup_by_name(dns_certificate_types, text);
+ if (type) {
+ id = htons((uint16_t) type->id);
+ } else {
+ char *end;
+ id = htons((uint16_t) strtol(text, &end, 10));
+ if (*end != '\0') {
+ zc_error_prev_line("certificate type is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ return NULL;
+ }
+ }
+
+ uint16_t *r = alloc_rdata_init(&id, sizeof(id));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ return r;
+}
+
+uint16_t * zparser_conv_a(const char *text)
+{
+ in_addr_t address;
+ uint16_t *r = NULL;
+
+ if (inet_pton(AF_INET, text, &address) != 1) {
+ zc_error_prev_line("invalid IPv4 address '%s'", text);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(&address, sizeof(address));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+
+ return r;
+}
+
+uint16_t * zparser_conv_aaaa(const char *text)
+{
+ uint8_t address[IP6ADDRLEN];
+ uint16_t *r = NULL;
+
+ if (inet_pton(AF_INET6, text, address) != 1) {
+ zc_error_prev_line("invalid IPv6 address '%s'", text);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(address, sizeof(address));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_text(const char *text, size_t len)
+{
+ uint16_t *r = NULL;
+
+ dbg_zp("Converting text: %s\n", text);
+
+ if (len > 255) {
+ zc_error_prev_line("text string is longer than 255 characters,"
+ " try splitting it into multiple parts");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ uint8_t *p;
+ r = alloc_rdata(len + 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ p = (uint8_t *)(r + 1);
+ *p = len;
+ memcpy(p + 1, text, len);
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_dns_name(const uint8_t *name, size_t len)
+{
+ uint16_t *r = NULL;
+ uint8_t *p = NULL;
+ r = alloc_rdata(len);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ p = (uint8_t *)(r + 1);
+ memcpy(p, name, len);
+
+ return r;
+}
+
+uint16_t * zparser_conv_b32(const char *b32)
+{
+ uint8_t buffer[B64BUFSIZE];
+ uint16_t *r = NULL;
+ size_t i = B64BUFSIZE - 1;
+
+ if (strcmp(b32, "-") == 0) {
+ r = alloc_rdata_init("", 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ return r;
+ }
+
+ /*!< \todo BLEEDING EYES! */
+
+ char b32_copy[strlen(b32) + 1];
+
+ for (int i = 0; i < strlen(b32); i++) {
+ b32_copy[i] = toupper(b32[i]);
+ }
+
+ /*!< \todo BLEEDING EYES! */
+ b32_copy[strlen(b32)] = '\0';
+
+ if (!base32hex_decode(b32_copy,
+ strlen(b32_copy), (char *)buffer + 1, &i)) {
+ zc_error_prev_line("invalid base32 data");
+ parser->error_occurred = 1;
+ } else {
+ buffer[0] = i; /* store length byte */
+ r = alloc_rdata_init(buffer, i + 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_b64(const char *b64)
+{
+ uint8_t buffer[B64BUFSIZE];
+ uint16_t *r = NULL;
+ int i;
+
+ i = b64_pton(b64, buffer, B64BUFSIZE);
+ if (i == -1) {
+ zc_error_prev_line("invalid base64 data\n");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(buffer, i);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_rrtype(const char *text)
+{
+ uint16_t *r = NULL;
+ uint16_t type = knot_rrtype_from_string(text);
+
+ if (type == 0) {
+ zc_error_prev_line("unrecognized RR type '%s'", text);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ type = htons(type);
+ r = alloc_rdata_init(&type, sizeof(type));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_nxt(uint8_t nxtbits[])
+{
+ /* nxtbits[] consists of 16 bytes with some zero's in it
+ * copy every byte with zero to r and write the length in
+ * the first byte
+ */
+ uint16_t i;
+ uint16_t last = 0;
+
+ for (i = 0; i < 16; i++) {
+ if (nxtbits[i] != 0) {
+ last = i + 1;
+ }
+ }
+
+ uint16_t *r = alloc_rdata_init(nxtbits, last);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ return r;
+}
+
+
+/* we potentially have 256 windows, each one is numbered. empty ones
+ * should be discarded
+ */
+uint16_t * zparser_conv_nsec(uint8_t nsecbits[NSEC_WINDOW_COUNT]
+ [NSEC_WINDOW_BITS_SIZE])
+{
+ /* nsecbits contains up to 64K of bits which represent the
+ * types available for a name. Walk the bits according to
+ * nsec++ draft from jakob
+ */
+ uint16_t *r;
+ uint8_t *ptr;
+ size_t i, j;
+ uint16_t window_count = 0;
+ uint16_t total_size = 0;
+ uint16_t window_max = 0;
+
+ /* The used windows. */
+ int used[NSEC_WINDOW_COUNT];
+ /* The last byte used in each the window. */
+ int size[NSEC_WINDOW_COUNT];
+
+ window_max = 1 + (nsec_highest_rcode / 256);
+
+ /* used[i] is the i-th window included in the nsec
+ * size[used[0]] is the size of window 0
+ */
+
+ /* walk through the 256 windows */
+ for (i = 0; i < window_max; ++i) {
+ int empty_window = 1;
+ /* check each of the 32 bytes */
+ for (j = 0; j < NSEC_WINDOW_BITS_SIZE; ++j) {
+ if (nsecbits[i][j] != 0) {
+ size[i] = j + 1;
+ empty_window = 0;
+ }
+ }
+ if (!empty_window) {
+ used[window_count] = i;
+ window_count++;
+ }
+ }
+
+ for (i = 0; i < window_count; ++i) {
+ total_size += sizeof(uint16_t) + size[used[i]];
+ }
+
+ r = alloc_rdata(total_size);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ return NULL;
+ }
+ ptr = (uint8_t *)(r + 1);
+
+ /* now walk used and copy it */
+ for (i = 0; i < window_count; ++i) {
+ ptr[0] = used[i];
+ ptr[1] = size[used[i]];
+ memcpy(ptr + 2, &nsecbits[used[i]], size[used[i]]);
+ ptr += size[used[i]] + 2;
+ }
+
+ return r;
+}
+
+/* Parse an int terminated in the specified range. */
+static int parse_int(const char *str,
+ char **end,
+ int *result,
+ const char *name,
+ int min,
+ int max)
+{
+ long value;
+ value = strtol(str, end, 10);
+ if (value < min || value > max) {
+ zc_error_prev_line("%s must be within the range [%d .. %d]",
+ name,
+ min,
+ max);
+ return 0;
+ } else {
+ *result = (int) value;
+ return 1;
+ }
+}
+
+/* RFC1876 conversion routines */
+static uint32_t poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+ 1000000, 10000000, 100000000, 1000000000
+ };
+
+/*
+ * Converts ascii size/precision X * 10**Y(cm) to 0xXY.
+ * Sets the given pointer to the last used character.
+ *
+ */
+static uint8_t precsize_aton(char *cp, char **endptr)
+{
+ unsigned int mval = 0, cmval = 0;
+ uint8_t retval = 0;
+ int exponent;
+ int mantissa;
+
+ while (isdigit((int)*cp)) {
+ mval = mval * 10 + hexdigit_to_int(*cp++);
+ }
+
+ if (*cp == '.') { /* centimeters */
+ cp++;
+ if (isdigit((int)*cp)) {
+ cmval = hexdigit_to_int(*cp++) * 10;
+ if (isdigit((int)*cp)) {
+ cmval += hexdigit_to_int(*cp++);
+ }
+ }
+ }
+
+ if (mval >= poweroften[7]) {
+ /* integer overflow possible for *100 */
+ mantissa = mval / poweroften[7];
+ exponent = 9; /* max */
+ } else {
+ cmval = (mval * 100) + cmval;
+
+ for (exponent = 0; exponent < 9; exponent++)
+ if (cmval < poweroften[exponent+1]) {
+ break;
+ }
+
+ mantissa = cmval / poweroften[exponent];
+ }
+ if (mantissa > 9) {
+ mantissa = 9;
+ }
+
+ retval = (mantissa << 4) | exponent;
+
+ if (*cp == 'm') {
+ cp++;
+ }
+
+ *endptr = cp;
+
+ return (retval);
+}
+
+/*
+ * Parses a specific part of rdata.
+ *
+ * Returns:
+ *
+ * number of elements parsed
+ * zero on error
+ *
+ */
+uint16_t * zparser_conv_loc(char *str)
+{
+ uint16_t *r;
+ uint32_t *p;
+ int i;
+ int deg, min, secs; /* Secs is stored times 1000. */
+ uint32_t lat = 0, lon = 0, alt = 0;
+ /* encoded defaults: version=0 sz=1m hp=10000m vp=10m */
+ uint8_t vszhpvp[4] = {0, 0x12, 0x16, 0x13};
+ char *start;
+ double d;
+
+ for (;;) {
+ deg = min = secs = 0;
+
+ /* Degrees */
+ if (*str == '\0') {
+ zc_error_prev_line("unexpected end of LOC data");
+ return NULL;
+ }
+
+ if (!parse_int(str, &str, &deg, "degrees", 0, 180)) {
+ return NULL;
+ }
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected after degrees");
+ return NULL;
+ }
+ ++str;
+
+ /* Minutes? */
+ if (isdigit((int)*str)) {
+ if (!parse_int(str, &str, &min, "minutes", 0, 60)) {
+ return NULL;
+ }
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected after minutes");
+ return NULL;
+ }
+ ++str;
+ }
+
+ /* Seconds? */
+ if (isdigit((int)*str)) {
+ start = str;
+ if (!parse_int(str, &str, &i, "seconds", 0, 60)) {
+ return NULL;
+ }
+
+ if (*str == '.' && !parse_int(str + 1, &str, &i,
+ "seconds fraction",
+ 0, 999)) {
+ return NULL;
+ }
+
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected after seconds");
+ return NULL;
+ }
+
+ if (sscanf(start, "%lf", &d) != 1) {
+ zc_error_prev_line("error parsing seconds");
+ }
+
+ if (d < 0.0 || d > 60.0) {
+ zc_error_prev_line(
+ "seconds not in range 0.0 .. 60.0");
+ }
+
+ secs = (int)(d * 1000.0 + 0.5);
+ ++str;
+ }
+
+ switch (*str) {
+ case 'N':
+ case 'n':
+ lat = ((uint32_t)1 << 31) +
+ (deg * 3600000 + min * 60000 + secs);
+ break;
+ case 'E':
+ case 'e':
+ lon = ((uint32_t)1 << 31) +
+ (deg * 3600000 + min * 60000 + secs);
+ break;
+ case 'S':
+ case 's':
+ lat = ((uint32_t)1 << 31) -
+ (deg * 3600000 + min * 60000 + secs);
+ break;
+ case 'W':
+ case 'w':
+ lon = ((uint32_t)1 << 31) -
+ (deg * 3600000 + min * 60000 + secs);
+ break;
+ default:
+ zc_error_prev_line(
+ "invalid latitude/longtitude: '%c'", *str);
+ return NULL;
+ }
+ ++str;
+
+ if (lat != 0 && lon != 0) {
+ break;
+ }
+
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected after"
+ " latitude/longitude");
+ return NULL;
+ }
+ ++str;
+ }
+
+ /* Altitude */
+ if (*str == '\0') {
+ zc_error_prev_line("unexpected end of LOC data");
+ return NULL;
+ }
+
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected before altitude");
+ return NULL;
+ }
+ ++str;
+
+ start = str;
+
+ /* Sign */
+ if (*str == '+' || *str == '-') {
+ ++str;
+ }
+
+ /* Meters of altitude... */
+ int ret = strtol(str, &str, 10);
+ UNUSED(ret); // Result checked in following switch
+
+ switch (*str) {
+ case ' ':
+ case '\0':
+ case 'm':
+ break;
+ case '.':
+ if (!parse_int(str + 1, &str, &i, "altitude fraction", 0, 99)) {
+ return NULL;
+ }
+ if (!isspace((int)*str) && *str != '\0' && *str != 'm') {
+ zc_error_prev_line("altitude fraction must be a number");
+ return NULL;
+ }
+ break;
+ default:
+ zc_error_prev_line("altitude must be expressed in meters");
+ return NULL;
+ }
+ if (!isspace((int)*str) && *str != '\0') {
+ ++str;
+ }
+
+ if (sscanf(start, "%lf", &d) != 1) {
+ zc_error_prev_line("error parsing altitude");
+ }
+
+ alt = (uint32_t)(10000000.0 + d * 100 + 0.5);
+
+ if (!isspace((int)*str) && *str != '\0') {
+ zc_error_prev_line("unexpected character after altitude");
+ return NULL;
+ }
+
+ /* Now parse size, horizontal precision and vertical precision if any */
+ for (i = 1; isspace((int)*str) && i <= 3; i++) {
+ vszhpvp[i] = precsize_aton(str + 1, &str);
+
+ if (!isspace((int)*str) && *str != '\0') {
+ zc_error_prev_line("invalid size or precision");
+ return NULL;
+ }
+ }
+
+ /* Allocate required space... */
+ r = alloc_rdata(16);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ p = (uint32_t *)(r + 1);
+
+ memmove(p, vszhpvp, 4);
+ write_uint32(p + 1, lat);
+ write_uint32(p + 2, lon);
+ write_uint32(p + 3, alt);
+
+ return r;
+}
+
+/*
+ * Convert an APL RR RDATA element.
+ */
+uint16_t * zparser_conv_apl_rdata(char *str)
+{
+ int negated = 0;
+ uint16_t address_family;
+ uint8_t prefix;
+ uint8_t maximum_prefix;
+ uint8_t length;
+ uint8_t address[IP6ADDRLEN];
+ char *colon = strchr(str, ':');
+ char *slash = strchr(str, '/');
+ int af;
+ int rc;
+ uint16_t rdlength;
+ uint16_t *r;
+ uint8_t *t;
+ char *end;
+ long p;
+
+ if (!colon) {
+ zc_error_prev_line("address family separator is missing");
+ return NULL;
+ }
+ if (!slash) {
+ zc_error_prev_line("prefix separator is missing");
+ return NULL;
+ }
+
+ *colon = '\0';
+ *slash = '\0';
+
+ if (*str == '!') {
+ negated = 1;
+ ++str;
+ }
+
+ if (strcmp(str, "1") == 0) {
+ address_family = htons(1);
+ af = AF_INET;
+ length = sizeof(in_addr_t);
+ maximum_prefix = length * 8;
+ } else if (strcmp(str, "2") == 0) {
+ address_family = htons(2);
+ af = AF_INET6;
+ length = IP6ADDRLEN;
+ maximum_prefix = length * 8;
+ } else {
+ zc_error_prev_line("invalid address family '%s'", str);
+ return NULL;
+ }
+
+ rc = inet_pton(af, colon + 1, address);
+ if (rc == 0) {
+ zc_error_prev_line("invalid address '%s'", colon + 1);
+ return NULL;
+ } else if (rc == -1) {
+ char ebuf[256];
+ zc_error_prev_line("inet_pton failed: %s",
+ strerror_r(errno, ebuf, sizeof(ebuf)));
+ return NULL;
+ }
+
+ /* Strip trailing zero octets. */
+ while (length > 0 && address[length - 1] == 0) {
+ --length;
+ }
+
+
+ p = strtol(slash + 1, &end, 10);
+ if (p < 0 || p > maximum_prefix) {
+ zc_error_prev_line("prefix not in the range 0 .. %d",
+ maximum_prefix);
+ return NULL;
+ } else if (*end != '\0') {
+ zc_error_prev_line("invalid prefix '%s'", slash + 1);
+ return NULL;
+ }
+ prefix = (uint8_t) p;
+
+ rdlength = (sizeof(address_family) + sizeof(prefix) + sizeof(length)
+ + length);
+ r = alloc_rdata(rdlength);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ t = (uint8_t *)(r + 1);
+
+ memcpy(t, &address_family, sizeof(address_family));
+ t += sizeof(address_family);
+ memcpy(t, &prefix, sizeof(prefix));
+ t += sizeof(prefix);
+ memcpy(t, &length, sizeof(length));
+ if (negated) {
+ *t |= APL_NEGATION_MASK;
+ }
+ t += sizeof(length);
+ memcpy(t, address, length);
+
+ return r;
+}
+
+/*
+ * Below some function that also convert but not to wireformat
+ * but to "normal" (int,long,char) types
+ */
+
+uint32_t zparser_ttl2int(const char *ttlstr, int *error)
+{
+ /* convert a ttl value to a integer
+ * return the ttl in a int
+ * -1 on error
+ */
+
+ uint32_t ttl;
+ const char *t;
+
+ ttl = strtottl(ttlstr, &t);
+ if (*t != 0) {
+ zc_error_prev_line("invalid TTL value: %s", ttlstr);
+ *error = 1;
+ }
+
+ return ttl;
+}
+
+void zadd_rdata_wireformat(uint16_t *data)
+{
+ parser->temporary_items[parser->rdata_count].raw_data = data;
+ parser->rdata_count++;
+}
+
+/**
+ * Used for TXT RR's to grow with undefined number of strings.
+ */
+void zadd_rdata_txt_wireformat(uint16_t *data, int first)
+{
+ dbg_zp("Adding text!\n");
+// hex_print(data + 1, data[0]);
+ knot_rdata_item_t *rd;
+
+ /* First STR in str_seq, allocate 65K in first unused rdata
+ * else find last used rdata */
+ if (first) {
+ rd = &parser->temporary_items[parser->rdata_count];
+// if ((rd->data = (uint8_t *) region_alloc(parser->rr_region,
+// sizeof(uint8_t) + 65535 * sizeof(uint8_t))) == NULL) {
+// zc_error_prev_line("Could not allocate memory for TXT RR");
+// return;
+// }
+ rd->raw_data = alloc_rdata(65535 * sizeof(uint8_t));
+ if (rd->raw_data == NULL) {
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ }
+ parser->rdata_count++;
+ rd->raw_data[0] = 0;
+ } else {
+// assert(0);
+ rd = &parser->temporary_items[parser->rdata_count-1];
+ }
+
+ if ((size_t)rd->raw_data[0] + (size_t)data[0] > 65535) {
+ zc_error_prev_line("too large rdata element");
+ return;
+ }
+
+ memcpy((uint8_t *)rd->raw_data + 2 + rd->raw_data[0],
+ data + 1, data[0]);
+ rd->raw_data[0] += data[0];
+ free(data);
+ dbg_zp("Item after add\n");
+// hex_print(rd->raw_data + 1, rd->raw_data[0]);
+}
+
+void zadd_rdata_domain(knot_dname_t *dname)
+{
+ knot_dname_retain(dname);
+// printf("Adding rdata name: %s %p\n", dname->name, dname);
+ parser->temporary_items[parser->rdata_count].dname = dname;
+ parser->rdata_count++;
+}
+
+void parse_unknown_rdata(uint16_t type, uint16_t *wireformat)
+{
+ dbg_rdata("parsing unknown rdata for type: %d\n", type);
+// buffer_type packet;
+ uint16_t size;
+ ssize_t rdata_count;
+ ssize_t i;
+ knot_rdata_item_t *items = NULL;
+
+ if (wireformat) {
+ size = *wireformat;
+ } else {
+ return;
+ }
+
+// buffer_create_from(&packet, wireformat + 1, *wireformat);
+ rdata_count = rdata_wireformat_to_rdata_atoms(wireformat + 1, type,
+ size, &items);
+// dbg_rdata("got %d items\n", rdata_count);
+ dbg_rdata("wf to items returned error: %s (%d)\n",
+ error_to_str(knot_zcompile_error_msgs, rdata_count),
+ rdata_count);
+ if (rdata_count < 0) {
+ zc_error_prev_line("bad unknown RDATA\n");
+ /*!< \todo leaks */
+ return;
+ }
+
+ for (i = 0; i < rdata_count; ++i) {
+ if (rdata_atom_is_domain(type, i)) {
+ zadd_rdata_domain(items[i].dname);
+ } else {
+ //XXX won't this create size two times?
+ zadd_rdata_wireformat((uint16_t *)items[i].raw_data);
+ }
+ }
+ free(items);
+ /* Free wireformat */
+ free(wireformat);
+}
+
+void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE],
+ uint16_t index)
+{
+ /*
+ * The bits are counted from left to right, so bit #0 is the
+ * left most bit.
+ */
+ uint8_t window = index / 256;
+ uint8_t bit = index % 256;
+
+ bits[window][bit / 8] |= (1 << (7 - bit % 8));
+}
+
diff --git a/src/zcompile/parser-util.h b/src/zcompile/parser-util.h
new file mode 100644
index 0000000..57258dc
--- /dev/null
+++ b/src/zcompile/parser-util.h
@@ -0,0 +1,357 @@
+/*!
+ * \file parser-util.h
+ *
+ * \author NLnet Labs
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ * Minor modifications by CZ.NIC, z.s.p.o.
+ *
+ * \brief Zone compiler utility functions.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KNOTD_PARSER_UTIL_H_
+#define _KNOTD_PARSER_UTIL_H_
+
+#include <assert.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "zcompile/zcompile.h"
+#include "libknot/util/descriptor.h"
+
+int inet_pton4(const char *src, uint8_t *dst);
+int inet_pton6(const char *src, uint8_t *dst);
+//int my_b32_pton(const char *src, uint8_t *target, size_t tsize);
+const char *inet_ntop4(const u_char *src, char *dst, size_t size);
+const char *inet_ntop6(const u_char *src, char *dst, size_t size);
+int inet_pton(int af, const char *src, void *dst);
+void b64_initialize_rmap();
+int b64_pton_do(char const *src, uint8_t *target, size_t targsize);
+int b64_pton_len(char const *src);
+int b64_pton(char const *src, uint8_t *target, size_t targsize);
+void set_bit(uint8_t bits[], size_t index);
+uint32_t strtoserial(const char *nptr, const char **endptr);
+void write_uint32(void *dst, uint32_t data);
+uint32_t strtottl(const char *nptr, const char **endptr);
+time_t mktime_from_utc(const struct tm *tm);
+
+/*!< Conversions from text to wire. */
+/*!
+ * \brief Converts hex text format to wireformat.
+ *
+ * \param hex String to be converted.
+ * \param len Length of string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_hex(const char *hex, size_t len);
+
+/*!
+ * \brief Converts hex text format with length to wireformat.
+ *
+ * \param hex String to be converted/.
+ * \param len Length of string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_hex_length(const char *hex, size_t len);
+
+/*!
+ * \brief Converts time string to wireformat.
+ *
+ * \param time Time string to be converted.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_time(const char *time);
+/*!
+ * \brief Converts a protocol and a list of service port numbers
+ * (separated by spaces) in the rdata to wireformat
+ *
+ * \param protostr Protocol string.
+ * \param servicestr Service string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_services(const char *protostr, char *servicestr);
+
+/*!
+ * \brief Converts serial to wireformat.
+ *
+ * \param serialstr Serial string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_serial(const char *serialstr);
+/*!
+ * \brief Converts period to wireformat.
+ *
+ * \param periodstr Period string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_period(const char *periodstr);
+
+/*!
+ * \brief Converts short int to wireformat.
+ *
+ * \param text String containing short int.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_short(const char *text);
+
+/*!
+ * \brief Converts long int to wireformat.
+ *
+ * \param text String containing long int.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_long(const char *text);
+
+/*!
+ * \brief Converts byte to wireformat.
+ *
+ * \param text String containing byte.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_byte(const char *text);
+
+/*!
+ * \brief Converts A rdata string to wireformat.
+ *
+ * \param text String containing A rdata.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_a(const char *text);
+
+/*!
+ * \brief Converts AAAA rdata string to wireformat.
+ *
+ * \param text String containing AAAA rdata.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_aaaa(const char *text);
+
+/*!
+ * \brief Converts text string to wireformat.
+ *
+ * \param text Text string.
+ * \param len Length of string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_text(const char *text, size_t len);
+
+/*!
+ * \brief Converts domain name string to wireformat.
+ *
+ * \param name Domain name string.
+ * \param len Length of string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_dns_name(const uint8_t* name, size_t len);
+
+/*!
+ * \brief Converts base32 encoded string to wireformat.
+ * TODO consider replacing with our implementation.
+ *
+ * \param b32 Base32 encoded string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_b32(const char *b32);
+
+/*!
+ * \brief Converts base64 encoded string to wireformat.
+ * TODO consider replacing with our implementation.
+ *
+ * \param b64 Base64 encoded string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_b64(const char *b64);
+
+/*!
+ * \brief Converts RR type string to wireformat.
+ *
+ * \param rr RR type string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_rrtype(const char *rr);
+
+/*!
+ * \brief Converts NXT string to wireformat.
+ *
+ * \param nxtbits NXT string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_nxt(uint8_t *nxtbits);
+
+/*!
+ * \brief Converts NSEC bitmap to wireformat.
+ *
+ * \param nsecbits[][] NSEC bits.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_nsec(uint8_t nsecbits[NSEC_WINDOW_COUNT]
+ [NSEC_WINDOW_BITS_SIZE]);
+/*!
+ * \brief Converts LOC string to wireformat.
+ *
+ * \param str LOC string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_loc(char *str);
+
+/*!
+ * \brief Converts algorithm string to wireformat.
+ *
+ * \param algstr Algorithm string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_algorithm(const char *algstr);
+
+/*!
+ * \brief Converts certificate type string to wireformat.
+ *
+ * \param typestr Certificate type mnemonic string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_certificate_type(const char *typestr);
+
+/*!
+ * \brief Converts APL data to wireformat.
+ *
+ * \param str APL data string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_apl_rdata(char *str);
+
+/*!
+ * \brief Parses unknown rdata.
+ *
+ * \param type Type of data.
+ * \param wireformat Wireformat of data.
+ *
+ * \return Converted wireformat.
+ */
+void parse_unknown_rdata(uint16_t type, uint16_t *wireformat);
+
+/*!
+ * \brief Converts TTL string to int.
+ *
+ * \param ttlstr String
+ * \param error Error code.
+ *
+ * \return Converted wireformat.
+ */
+uint32_t zparser_ttl2int(const char *ttlstr, int* error);
+
+/*!
+ * \brief Adds wireformat to temporary list of rdata items.
+ *
+ * \param data Wireformat to be added.
+ */
+void zadd_rdata_wireformat(uint16_t *data);
+
+/*!
+ * \brief Adds TXT wireformat to temporary list of rdata items.
+ *
+ * \param data Wireformat to be added.
+ * \param first This is first text to be added.
+ */
+void zadd_rdata_txt_wireformat(uint16_t *data, int first);
+
+/*!
+ * \brief Cleans after using zadd_rdata_txt_wireformat().
+ */
+void zadd_rdata_txt_clean_wireformat();
+
+/*!
+ * \brief Adds domain name to temporary list of rdata items.
+ *
+ * \param domain Domain name to be added.
+ */
+void zadd_rdata_domain(knot_dname_t *domain);
+
+/*!
+ * \brief Sets bit in NSEC bitmap.
+ *
+ * \param bits[][] NSEC bitmaps.
+ * \param index Index on which bit is to be set.
+ */
+void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE],
+ uint16_t index);
+
+/*!
+ * \brief Allocate and init wireformat.
+ *
+ * \param data Data to be copied into newly created wireformat.
+ * \param size Size of data.
+ *
+ * \return Allocated wireformat.
+ */
+uint16_t *alloc_rdata_init(const void *data, size_t size);
+uint16_t rrsig_type_covered(knot_rrset_t *rrset);
+
+
+#endif /* _KNOTD_PARSER_UTIL_H_ */
+
+/*! @} */
diff --git a/src/zcompile/tests/unittests_zp_main.c b/src/zcompile/tests/unittests_zp_main.c
new file mode 100644
index 0000000..5d8c5e9
--- /dev/null
+++ b/src/zcompile/tests/unittests_zp_main.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "knot/common.h"
+#include "common/libtap/tap_unit.h"
+
+// Units to test
+#include "zcompile_tests.c"
+
+// Run all loaded units
+int main(int argc, char *argv[])
+{
+ // Open log
+ //log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING));
+
+ // Build test set
+ unit_api *tests[] = {
+ &zoneparser_tests_api, //! Zoneparser unit
+ NULL
+ };
+
+ // Plan number of tests
+ int id = 0;
+ int test_count = 0;
+ note("Units:");
+ while (tests[id] != NULL) {
+ note("- %s : %d tests", tests[id]->name,
+ tests[id]->count(argc, argv));
+ test_count += tests[id]->count(argc, argv);
+ ++id;
+ }
+
+ plan(test_count);
+
+ // Run tests
+ id = 0;
+ while (tests[id] != NULL) {
+ diag("Testing unit: %s", tests[id]->name);
+ tests[id]->run(argc, argv);
+ ++id;
+ }
+
+ //log_close();
+
+ // Evaluate
+ return exit_status();
+}
+
diff --git a/src/zcompile/tests/zcompile_tests.c b/src/zcompile/tests/zcompile_tests.c
new file mode 100644
index 0000000..5d3dce6
--- /dev/null
+++ b/src/zcompile/tests/zcompile_tests.c
@@ -0,0 +1,425 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libknot/zone/zone.h"
+#include "knot/zone/zone-load.h"
+#include "knot/common.h"
+#include "libknot/rrset.h"
+#include "libknot/util/descriptor.h"
+#include "zcompile/zcompile.h"
+
+#ifdef TEST_WITH_LDNS
+#include "ldns/ldns.h"
+#endif
+
+static int zoneparser_tests_count(int argc, char *argv[]);
+static int zoneparser_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api zoneparser_tests_api = {
+ "Zoneparser",
+ &zoneparser_tests_count,
+ &zoneparser_tests_run
+};
+
+#ifdef TEST_WITH_LDNS
+/*
+ * Unit implementation.
+ */static int compare_wires_simple_zp(uint8_t *wire1,
+ uint8_t *wire2, uint count)
+{
+ int i = 0;
+ while (i < count &&
+ wire1[i] == wire2[i]) {
+ i++;
+ }
+ return (!(count == i));
+}
+
+/* compares only one rdata */
+static int compare_rr_rdata_silent(knot_rdata_t *rdata, ldns_rr *rr,
+ uint16_t type)
+{
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ for (int i = 0; i < rdata->count; i++) {
+ /* TODO check for ldns "descriptors" as well */
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) {
+ assert(ldns_rr_rdf(rr, i));
+ if (rdata->items[i].dname->size !=
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) {
+ return 1;
+ }
+ if (compare_wires_simple_zp(rdata->items[i].dname->name,
+ ldns_rdf_data(ldns_rr_rdf(rr, i)),
+ rdata->items[i].dname->size) != 0) {
+ return 1;
+ }
+ } else {
+ if (ldns_rr_rdf(rr, i) == NULL &&
+ rdata->items[i].raw_data[0] != 0) {
+ return 1;
+ } else {
+ continue;
+ }
+ if (rdata->items[i].raw_data[0] !=
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) {
+
+ /* ldns stores the size including the
+ * length, dnslib does not */
+ if (abs(rdata->items[i].raw_data[0] -
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) != 1) {
+ return 1;
+ }
+ }
+ if (compare_wires_simple_zp((uint8_t *)
+ (rdata->items[i].raw_data + 1),
+ ldns_rdf_data(ldns_rr_rdf(rr, i)),
+ rdata->items[i].raw_data[0]) != 0) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int compare_rrset_w_ldns_rrset(const knot_rrset_t *rrset,
+ ldns_rr_list *rrs,
+ char check_rdata, char verbose)
+{
+ /* We should have only one rrset from ldns, although it is
+ * represented as rr_list ... */
+
+ /* TODO errors */
+
+ assert(rrs);
+ assert(rrset);
+
+ ldns_rr_list_sort(rrs);
+
+ /* compare headers */
+
+ ldns_rr *rr = ldns_rr_list_rr(rrs, 0);
+
+ if (rrset->owner->size != ldns_rdf_size(ldns_rr_owner(rr))) {
+ diag("RRSet owner names differ in length");
+ if (!verbose) {
+ return 1;
+ }
+ diag("ldns: %d, dnslib: %d", ldns_rdf_size(ldns_rr_owner(rr)),
+ rrset->owner->size);
+ diag("%s", knot_dname_to_str(rrset->owner));
+ diag("%s", ldns_rdf_data(ldns_rr_owner(rr)));
+ return 1;
+ }
+
+ if (compare_wires_simple_zp(rrset->owner->name,
+ ldns_rdf_data(ldns_rr_owner(rr)),
+ rrset->owner->size) != 0) {
+ diag("RRSet owner wireformats differ");
+ return 1;
+ }
+
+ if (rrset->type != ldns_rr_get_type(rr)) {
+ diag("RRset types differ");
+ if (!verbose) {
+ return 1;
+ }
+ diag("Dnslib type: %d Ldns type: %d", rrset->type,
+ ldns_rr_get_type(rr));
+ return 1;
+ }
+
+ if (rrset->rclass != ldns_rr_get_class(rr)) {
+ diag("RRset classes differ");
+ return 1;
+ }
+
+ if (rrset->ttl != ldns_rr_ttl(rr)) {
+ diag("RRset TTLs differ");
+ if (!verbose) {
+ return 1;
+ }
+ diag("dnslib: %d ldns: %d", rrset->ttl, ldns_rr_ttl(rr));
+ return 1;
+ }
+
+ if (!check_rdata) {
+ return 0;
+ }
+
+ /* compare rdatas */
+
+ /* sort dnslib rdata */
+
+ knot_rdata_t *tmp_rdata = rrset->rdata;
+
+ rr = ldns_rr_list_pop_rr(rrs);
+
+ char found;
+
+ while (rr != NULL) {
+ found = 0;
+ tmp_rdata = rrset->rdata;
+ while (!found &&
+ tmp_rdata->next != rrset->rdata) {
+ if (compare_rr_rdata_silent(tmp_rdata, rr,
+ rrset->type) == 0) {
+ found = 1;
+ }
+ tmp_rdata = tmp_rdata->next;
+ }
+
+ if (!found &&
+ compare_rr_rdata_silent(tmp_rdata, rr, rrset->type) == 0) {
+ found = 1;
+ }
+
+ /* remove the found rdata from list */
+ if (!found) {
+ diag("RRsets rdata differ");
+ return 1;
+ }
+ ldns_rr_free(rr);
+
+ rr = ldns_rr_list_pop_rr(rrs);
+ }
+
+ return 0;
+}
+
+int compare_zones(knot_zone_contents_t *zone,
+ ldns_rr_list *ldns_list, char verbose)
+{
+ /* TODO currently test fail when encountering first error -
+ * it should finish going through the zone */
+ knot_rrset_t *tmp_rrset = NULL;
+
+ knot_dname_t *tmp_dname = NULL;
+
+ knot_node_t *node = NULL;
+
+ ldns_rr_list *ldns_rrset = ldns_rr_list_pop_rrset(ldns_list);
+
+ if (ldns_rrset == NULL) {
+ diag("Error: empty node");
+ return 1;
+ }
+
+ ldns_rr *rr = NULL;
+
+ /*
+ * Following cycle works like this: First, we get RR from ldns rrset,
+ * then we search for the node containing the rrset, then we get the
+ * rrset, which is then compared with whole ldns rrset.
+ */
+
+ /* ldns_rr_list_pop_rrset should pop the first rrset */
+ while (ldns_rrset != NULL) {
+ rr = ldns_rr_list_rr(ldns_rrset, 0);
+ tmp_dname =
+ knot_dname_new_from_wire(ldns_rdf_data(ldns_rr_owner(rr)),
+ ldns_rdf_size(ldns_rr_owner(rr)),
+ NULL);
+
+ node = knot_zone_contents_get_node(zone, tmp_dname);
+
+ if (node == NULL) {
+ node = knot_zone_contents_get_nsec3_node(zone,
+ tmp_dname);
+ }
+
+ if (node == NULL) {
+ diag("Could not find node");
+ diag("%s", knot_dname_to_str(tmp_dname));
+ return 1;
+ }
+
+ knot_dname_free(&tmp_dname);
+
+ tmp_rrset = knot_node_get_rrset(node,
+ ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset,
+ 0)));
+
+ if (tmp_rrset == NULL &&
+ (uint)(ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset, 0))) !=
+ (uint)KNOT_RRTYPE_RRSIG) {
+ diag("Could not find rrset");
+ if (!verbose) {
+ return 1;
+ }
+ ldns_rr_list_print(stdout, ldns_rrset);
+ diag("%s", knot_dname_to_str(node->owner));
+ return 1;
+ } else if ((uint)(ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset,
+ 0))) ==
+ (uint)KNOT_RRTYPE_RRSIG) {
+ knot_rrset_t *rrsigs = NULL;
+ /* read type covered from ldns rrset */
+ for (int i = 0; i < ldns_rrset->_rr_count; i++) {
+ uint16_t type_covered =
+ ldns_rdf_data(ldns_rr_rdf(
+ ldns_rr_list_rr(ldns_rrset, i), 0))[1];
+
+ /*
+ * Dnslib stores RRSIGs separately -
+ * we have to find get it from its "parent"
+ * rrset.
+ */
+
+ tmp_rrset = knot_node_get_rrset(node,
+ type_covered);
+
+ if (tmp_rrset == NULL) {
+ if (!verbose) {
+ return 1;
+ }
+ diag("following rrset "
+ "could not be found");
+ ldns_rr_list_print(stdout, ldns_rrset);
+ return 1;
+ }
+
+ if (rrsigs == NULL) {
+ rrsigs = tmp_rrset->rrsigs;
+ } else {
+ knot_rrset_merge((void *)&rrsigs,
+ (void *)&(tmp_rrset->rrsigs));
+ }
+ }
+ tmp_rrset = rrsigs;
+ }
+
+/* diag("dnslib type: %d", tmp_rrset->type);
+ diag("dnslib dname: %s", tmp_rrset->owner->name);
+
+ diag("ldns type: %d",
+ ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset, 0)));
+ diag("ldns dname : %s", ldns_rdf_data(ldns_rr_owner(
+ ldns_rr_list_rr(ldns_rrset, 0)))); */
+
+// knot_rrset_dump(tmp_rrset, 1);
+
+ if (compare_rrset_w_ldns_rrset(tmp_rrset, ldns_rrset,
+ 1, 0) != 0) {
+ diag("RRSets did not match");
+// knot_rrset_dump(tmp_rrset, 1);
+ return 1;
+ }
+
+ ldns_rr_list_deep_free(ldns_rrset);
+
+ ldns_rrset = ldns_rr_list_pop_rrset(ldns_list);
+
+ if (ldns_rrset == NULL) {
+ ldns_rrset = ldns_rr_list_pop_rrset(ldns_list);
+ }
+ }
+
+ return 0;
+}
+
+#endif
+
+static int test_zoneparser_zone_read(const char *origin, const char *filename,
+ const char *outfile)
+{
+#ifndef TEST_WITH_LDNS
+ diag("Zoneparser tests without usage of ldns are not implemented");
+ return 0;
+#endif
+
+#ifdef TEST_WITH_LDNS
+ /* Calls zcompile. */
+ parser = zparser_create();
+ int ret = zone_read(origin, filename, outfile, 0);
+ if (ret != 0) {
+ diag("Could not load zone from file: %s", filename);
+ return 0;
+ }
+
+ knot_zone_t *dnsl_zone = NULL;
+ zloader_t *loader = NULL;
+ if (knot_zload_open(&loader, outfile) != 0) {
+ diag("Could not create zone loader.\n");
+ return 0;
+ }
+ dnsl_zone = knot_zload_load(loader);
+ remove(outfile);
+ if (!dnsl_zone) {
+ diag("Could not load dumped zone.\n");
+ return 0;
+ }
+
+ ldns_zone *ldns_zone = NULL;
+ FILE *f = fopen(filename, "r");
+ if (ldns_zone_new_frm_fp(&ldns_zone, f, NULL,
+ 0, LDNS_RR_CLASS_IN) != LDNS_STATUS_OK) {
+ diag("Could not load zone from file: %s (ldns)", filename);
+ return 0;
+ }
+
+// ldns_zone_sort(ldns_zone);
+
+ /*
+ * LDNS stores SOA record independently - create a list with all
+ * records in it.
+ */
+
+ ldns_rr_list *ldns_list = ldns_zone_rrs(ldns_zone);
+
+ ldns_rr_list_push_rr(ldns_list, ldns_zone_soa(ldns_zone));
+
+ if (compare_zones(dnsl_zone->contents, ldns_list, 0) != 0) {
+ return 0;
+ }
+
+ knot_zone_deep_free(&dnsl_zone, 0);
+ ldns_zone_free(ldns_zone);
+ fclose(f);
+ return 1;
+#endif
+}
+
+static const int ZONEPARSER_TEST_COUNT = 1;
+
+/*! API: return number of tests. */
+static int zoneparser_tests_count(int argc, char *argv[])
+{
+ return ZONEPARSER_TEST_COUNT;
+}
+
+/*! API: run tests. */
+static int zoneparser_tests_run(int argc, char *argv[])
+{
+ if (argc == 3) {
+ ok(test_zoneparser_zone_read(argv[1], argv[2],
+ "foo_test_zone"),
+ "zoneparser: read (%s)",
+ argv[2]);
+ } else {
+ diag("Wrong parameters\n usage: "
+ "knot-zcompile-unittests origin zonefile");
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/zcompile/zcompile-error.c b/src/zcompile/zcompile-error.c
new file mode 100644
index 0000000..9357cde
--- /dev/null
+++ b/src/zcompile/zcompile-error.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "zcompile/zcompile-error.h"
+
+#include "common/errors.h"
+
+/*! \brief Table linking error messages to error codes. */
+const error_table_t knot_zcompile_error_msgs[KNOTDZCOMPILE_ERROR_COUNT] = {
+
+ /* Mapped errors. */
+ {KNOTDZCOMPILE_EOK, "OK"},
+ {KNOTDZCOMPILE_ENOMEM, "Not enough memory."},
+ {KNOTDZCOMPILE_EINVAL, "Invalid parameter passed."},
+ {KNOTDZCOMPILE_ENOTSUP, "Parameter not supported."},
+ {KNOTDZCOMPILE_EBUSY, "Requested resource is busy."},
+ {KNOTDZCOMPILE_EAGAIN,
+ "The system lacked the necessary resource, try again."},
+ {KNOTDZCOMPILE_EACCES,
+ "Permission to perform requested operation is denied."},
+ {KNOTDZCOMPILE_ECONNREFUSED, "Connection is refused."},
+ {KNOTDZCOMPILE_EISCONN, "Already connected."},
+ {KNOTDZCOMPILE_EADDRINUSE, "Address already in use."},
+ {KNOTDZCOMPILE_ENOENT, "Resource not found."},
+ {KNOTDZCOMPILE_ERANGE, "Value is out of range."},
+
+ /* Custom errors. */
+ {KNOTDZCOMPILE_ERROR, "Generic error."},
+ {KNOTDZCOMPILE_EBRDATA, "Malformed RDATA."},
+ {KNOTDZCOMPILE_ESOA, "Multiple SOA records."},
+ {KNOTDZCOMPILE_EBADSOA, "SOA record has different owner "
+ "than in config - parser will not continue!"},
+ {KNOTDZCOMPILE_EBADNODE, "Error handling node."},
+ {KNOTDZCOMPILE_EZONEINVAL, "Invalid zone file."},
+ {KNOTDZCOMPILE_EPARSEFAIL, "Parser failed."},
+ {KNOTDZCOMPILE_ENOIPV6, "IPv6 support disabled."},
+ {KNOTDZCOMPILE_ESYNT, "Parser syntactic error."},
+ {KNOTDZCOMPILE_ERROR, 0}
+};
diff --git a/src/zcompile/zcompile-error.h b/src/zcompile/zcompile-error.h
new file mode 100644
index 0000000..c6d999c
--- /dev/null
+++ b/src/zcompile/zcompile-error.h
@@ -0,0 +1,90 @@
+/*!
+ * \file zcompile-error.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief Error codes and function for getting error message.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_ZCOMPILE_ERROR_H_
+#define _KNOTD_ZCOMPILE_ERROR_H_
+
+#include "common/errors.h"
+
+/*!
+ * \brief Error codes used in the server.
+ *
+ * Some viable errors are directly mapped
+ * to libc errno codes.
+ */
+enum knot_zcompile_error {
+
+ /* Directly mapped error codes. */
+ KNOTDZCOMPILE_EOK = 0,
+ KNOTDZCOMPILE_ENOMEM = -ENOMEM, /*!< \brief Out of memory. */
+ KNOTDZCOMPILE_EINVAL = -EINVAL, /*!< \brief Invalid parameter passed. */
+ /*!
+ * \brief Parameter not supported.
+ */
+ KNOTDZCOMPILE_ENOTSUP = -ENOTSUP,
+ KNOTDZCOMPILE_EBUSY = -EBUSY, /*!< \brief Requested resource is busy. */
+ /*!
+ * \brief OS lacked necessary resources.
+ */
+ KNOTDZCOMPILE_EAGAIN = -EAGAIN,
+ KNOTDZCOMPILE_EACCES = -EACCES, /*!< \brief Permission is denied. */
+ /*!
+ * \brief Connection is refused.
+ */
+ KNOTDZCOMPILE_ECONNREFUSED = -ECONNREFUSED,
+ KNOTDZCOMPILE_EISCONN = -EISCONN, /*!< \brief Already connected. */
+ /*!
+ * \brief Address already in use.
+ */
+ KNOTDZCOMPILE_EADDRINUSE = -EADDRINUSE,
+ KNOTDZCOMPILE_ENOENT = -ENOENT, /*!< \brief Resource not found. */
+ KNOTDZCOMPILE_ERANGE = -ERANGE, /*!< \brief Value is out of range. */
+
+ /* Custom error codes. */
+ KNOTDZCOMPILE_ERROR = -16384, /*!< \brief Generic error. */
+ KNOTDZCOMPILE_ESYNT, /*!< \brief Syntax error. */
+ KNOTDZCOMPILE_EBADNODE, /*!< \brief Node error. */
+ KNOTDZCOMPILE_EBRDATA, /*!< \brief RDATA error. */
+ KNOTDZCOMPILE_EBADSOA, /*!< \brief SOA owner error. */
+ KNOTDZCOMPILE_ESOA, /*!< \brief Multiple SOA records. */
+
+ KNOTDZCOMPILE_EZONEINVAL, /*!< \brief Invalid zone file. */
+ KNOTDZCOMPILE_EPARSEFAIL, /*!< \brief Parser fail. */
+ KNOTDZCOMPILE_ENOIPV6, /*! \brief No IPv6 support. */
+
+ KNOTDZCOMPILE_ERROR_COUNT = 22
+};
+
+typedef enum knot_zcompile_error knot_zcompile_error_t;
+
+/*! \brief Table linking error messages to error codes. */
+extern const error_table_t knot_zcompile_error_msgs[KNOTDZCOMPILE_ERROR_COUNT];
+
+#endif /* _KNOTD_ZCOMPILE_ERROR_H_ */
+
+/*! @} */
diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c
new file mode 100644
index 0000000..ec3cbe2
--- /dev/null
+++ b/src/zcompile/zcompile.c
@@ -0,0 +1,639 @@
+/*!
+ * \file zcompile.c
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>. Minor portions of code taken from
+ * NSD.
+ *
+ * \brief Zone compiler.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "common/base32hex.h"
+#include "zcompile/zcompile.h"
+#include "zcompile/parser-util.h"
+#include "knot/zone/zone-dump-text.h"
+#include "zparser.h"
+#include "zcompile/zcompile-error.h"
+#include "knot/zone/zone-dump.h"
+#include "libknot/libknot.h"
+#include "libknot/util/utils.h"
+
+/* Some global flags... */
+static int vflag = 0;
+/* if -v then print progress each 'progress' RRs */
+static int progress = 10000;
+
+/* Total errors counter */
+static long int totalerrors = 0;
+static long int totalrrs = 0;
+
+extern FILE *zp_get_in(void *scanner);
+
+//#define ZP_DEBUG
+
+#ifdef ZP_DEBUG
+#define dbg_zp(msg...) fprintf(stderr, msg)
+#else
+#define dbg_zp(msg...)
+#endif
+
+/*!
+ * \brief Adds RRSet to list.
+ *
+ * \param head Head of list.
+ * \param rrsig RRSet to be added.
+ */
+static int rrset_list_add(rrset_list_t **head, knot_rrset_t *rrsig)
+{
+ if (*head == NULL) {
+ *head = malloc(sizeof(rrset_list_t));
+ if (*head == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+ (*head)->next = NULL;
+ (*head)->data = rrsig;
+ } else {
+ rrset_list_t *tmp = malloc(sizeof(*tmp));
+ if (tmp == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+ tmp->next = *head;
+ tmp->data = rrsig;
+ *head = tmp;
+ }
+
+ return KNOTDZCOMPILE_EOK;
+}
+
+/*!
+ * \brief Deletes RRSet list. Sets pointer to NULL.
+ *
+ * \param head Head of list to be deleted.
+ */
+static void rrset_list_delete(rrset_list_t **head)
+{
+ rrset_list_t *tmp;
+ if (*head == NULL) {
+ return;
+ }
+
+ while (*head != NULL) {
+ tmp = *head;
+ *head = (*head)->next;
+ free(tmp);
+ }
+
+ *head = NULL;
+}
+
+static int find_rrset_for_rrsig_in_zone(knot_zone_contents_t *zone,
+ knot_rrset_t *rrsig)
+{
+ assert(rrsig != NULL);
+ assert(rrsig->rdata->items[0].raw_data);
+
+ knot_node_t *tmp_node = NULL;
+
+ if (rrsig->type != KNOT_RRTYPE_NSEC3) {
+ tmp_node = knot_zone_contents_get_node(zone, rrsig->owner);
+ } else {
+ tmp_node = knot_zone_contents_get_nsec3_node(zone,
+ rrsig->owner);
+ }
+
+ if (tmp_node == NULL) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+
+ knot_rrset_t *tmp_rrset =
+ knot_node_get_rrset(tmp_node, rrsig->type);
+
+ if (tmp_rrset == NULL) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+
+ if (tmp_rrset->rrsigs != NULL) {
+ knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node,
+ KNOT_RRSET_DUPL_MERGE, 1);
+ knot_rrset_free(&rrsig);
+ } else {
+ knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node,
+ KNOT_RRSET_DUPL_SKIP, 1);
+ }
+
+ return KNOTDZCOMPILE_EOK;
+}
+
+static int find_rrset_for_rrsig_in_node(knot_zone_contents_t *zone,
+ knot_node_t *node,
+ knot_rrset_t *rrsig)
+{
+ assert(rrsig != NULL);
+ assert(rrsig->rdata->items[0].raw_data);
+ assert(node);
+
+ assert(knot_dname_compare(rrsig->owner, node->owner) == 0);
+
+ knot_rrset_t *tmp_rrset =
+ knot_node_get_rrset(node, rrsig_type_covered(rrsig));
+
+ if (tmp_rrset == NULL) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+
+ if (tmp_rrset->rrsigs != NULL) {
+ if (knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node,
+ KNOT_RRSET_DUPL_MERGE, 1) < 0) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+ knot_rrset_free(&rrsig);
+ } else {
+ if (knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node,
+ KNOT_RRSET_DUPL_SKIP, 1) < 0) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+ }
+
+ assert(tmp_rrset->rrsigs != NULL);
+
+ return KNOTDZCOMPILE_EOK;
+}
+
+static knot_node_t *create_node(knot_zone_contents_t *zone,
+ knot_rrset_t *current_rrset,
+ int (*node_add_func)(knot_zone_contents_t *zone, knot_node_t *node,
+ int create_parents, uint8_t, int),
+ knot_node_t *(*node_get_func)(const knot_zone_contents_t *zone,
+ const knot_dname_t *owner))
+{
+ knot_node_t *node =
+ knot_node_new(current_rrset->owner, NULL, 0);
+ if (node_add_func(zone, node, 1, 0, 1) != 0) {
+ return NULL;
+ }
+
+ current_rrset->owner = node->owner;
+
+ return node;
+}
+
+static void process_rrsigs_in_node(knot_zone_contents_t *zone,
+ knot_node_t *node)
+{
+ rrset_list_t *tmp = parser->node_rrsigs;
+ while (tmp != NULL) {
+ if (find_rrset_for_rrsig_in_node(zone, node,
+ tmp->data) != 0) {
+ rrset_list_add(&parser->rrsig_orphans,
+ tmp->data);
+ parser->rrsig_orphan_count++;
+ }
+ tmp = tmp->next;
+ }
+}
+
+int process_rr(void)
+{
+ knot_zone_t *zone = parser->current_zone;
+ assert(zone != NULL);
+ knot_zone_contents_t *contents = knot_zone_get_contents(zone);
+ assert(contents != NULL);
+ knot_rrset_t *current_rrset = parser->current_rrset;
+ knot_rrset_t *rrset;
+ knot_rrtype_descriptor_t *descriptor =
+ knot_rrtype_descriptor_by_type(current_rrset->type);
+
+ dbg_zp("%s\n", knot_dname_to_str(parser->current_rrset->owner));
+ dbg_zp("type: %s\n", knot_rrtype_to_string(parser->current_rrset->type));
+ dbg_zp("rdata count: %d\n", parser->current_rrset->rdata->count);
+// hex_print(parser->current_rrset->rdata->items[0].raw_data,
+// parser->current_rrset->rdata->items[0].raw_data[0]);
+
+ if (descriptor->fixed_items) {
+ assert(current_rrset->rdata->count == descriptor->length);
+ }
+
+ assert(current_rrset->rdata->count > 0);
+
+ assert(knot_dname_is_fqdn(current_rrset->owner));
+
+ int (*node_add_func)(knot_zone_contents_t *, knot_node_t *, int,
+ uint8_t, int);
+ knot_node_t *(*node_get_func)(const knot_zone_contents_t *,
+ const knot_dname_t *);
+
+
+ /* If we have RRSIG of NSEC3 type first node will have
+ * to be created in NSEC3 part of the zone */
+
+ uint16_t type_covered = 0;
+ if (current_rrset->type == KNOT_RRTYPE_RRSIG) {
+ type_covered = rrsig_type_covered(current_rrset);
+ }
+
+ if (current_rrset->type != KNOT_RRTYPE_NSEC3 &&
+ type_covered != KNOT_RRTYPE_NSEC3) {
+ node_add_func = &knot_zone_contents_add_node;
+ node_get_func = &knot_zone_contents_get_node;
+ } else {
+ node_add_func = &knot_zone_contents_add_nsec3_node;
+ node_get_func = &knot_zone_contents_get_nsec3_node;
+ }
+
+ if ((current_rrset->type == KNOT_RRTYPE_SOA) && (zone != NULL)) {
+ if (knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA) != NULL) {
+ /* Receiving another SOA. */
+ if (!knot_rrset_compare(current_rrset,
+ knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA), KNOT_RRSET_COMPARE_WHOLE)) {
+ return KNOTDZCOMPILE_ESOA;
+ } else {
+ zc_warning_prev_line("encountered identical "
+ "extra SOA record");
+ return KNOTDZCOMPILE_EOK;
+ }
+ }
+ }
+
+ /*!< \todo Make sure the maximum RDLENGTH does not exceed 65535 bytes.*/
+
+ if (current_rrset->type == KNOT_RRTYPE_SOA) {
+ if (knot_dname_compare(current_rrset->owner,
+ parser->origin_from_config) != 0) {
+ zc_error_prev_line("SOA record has a different "
+ "owner than the one specified "
+ "in config! \n");
+ /* Such SOA cannot even be added, because
+ * it would not be in the zone apex. */
+ return KNOTDZCOMPILE_EBADSOA;
+ }
+ }
+
+ if (current_rrset->type == KNOT_RRTYPE_RRSIG) {
+ /*!< \todo Still a leak somewhere. */
+ knot_rrset_t *tmp_rrsig =
+ knot_rrset_new(current_rrset->owner,
+ KNOT_RRTYPE_RRSIG,
+ current_rrset->rclass,
+ current_rrset->ttl);
+ if (tmp_rrsig == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ if (knot_rrset_add_rdata(tmp_rrsig,
+ current_rrset->rdata) != 0) {
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+
+ if (parser->last_node &&
+ knot_dname_compare(parser->last_node->owner,
+ current_rrset->owner) != 0) {
+ /* RRSIG is first in the node, so we have to create it
+ * before we return
+ */
+ if (parser->node_rrsigs != NULL) {
+ process_rrsigs_in_node(contents,
+ parser->last_node);
+ rrset_list_delete(&parser->node_rrsigs);
+ }
+
+ if ((parser->last_node = create_node(contents,
+ current_rrset, node_add_func,
+ node_get_func)) == NULL) {
+ knot_rrset_free(&tmp_rrsig);
+ return KNOTDZCOMPILE_EBADNODE;
+ }
+ }
+
+ if (rrset_list_add(&parser->node_rrsigs, tmp_rrsig) != 0) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ return KNOTDZCOMPILE_EOK;
+ }
+
+ assert(current_rrset->type != KNOT_RRTYPE_RRSIG);
+
+ knot_node_t *node = NULL;
+ /* \note this could probably be much simpler */
+ if (parser->last_node && current_rrset->type != KNOT_RRTYPE_SOA &&
+ knot_dname_compare(parser->last_node->owner,
+ current_rrset->owner) ==
+ 0) {
+ node = parser->last_node;
+ } else {
+ if (parser->last_node && parser->node_rrsigs) {
+ process_rrsigs_in_node(contents,
+ parser->last_node);
+ }
+
+ rrset_list_delete(&parser->node_rrsigs);
+
+ /* new node */
+ node = node_get_func(contents, current_rrset->owner);
+ }
+
+ if (node == NULL) {
+ if (parser->last_node && parser->node_rrsigs) {
+ process_rrsigs_in_node(contents,
+ parser->last_node);
+ }
+
+ if ((node = create_node(contents, current_rrset,
+ node_add_func,
+ node_get_func)) == NULL) {
+ return KNOTDZCOMPILE_EBADNODE;
+ }
+ }
+
+ rrset = knot_node_get_rrset(node, current_rrset->type);
+ if (!rrset) {
+ rrset = knot_rrset_new(current_rrset->owner,
+ current_rrset->type,
+ current_rrset->rclass,
+ current_rrset->ttl);
+ if (rrset == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ if (knot_rrset_add_rdata(rrset, current_rrset->rdata) != 0) {
+ free(rrset);
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+
+ /* I chose skip, but there should not really be
+ * any rrset to skip */
+ if (knot_zone_contents_add_rrset(contents, rrset, &node,
+ KNOT_RRSET_DUPL_SKIP, 1) < 0) {
+ free(rrset);
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+ } else {
+ if (current_rrset->type !=
+ KNOT_RRTYPE_RRSIG && rrset->ttl !=
+ current_rrset->ttl) {
+ zc_error_prev_line(
+ "TTL does not match the TTL of the RRset");
+ }
+
+ if (knot_zone_contents_add_rrset(contents, current_rrset,
+ &node,
+ KNOT_RRSET_DUPL_MERGE, 1) < 0) {
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+ }
+
+ if (vflag > 1 && totalrrs > 0 && (totalrrs % progress == 0)) {
+ zc_error_prev_line("Total errors: %ld\n", totalrrs);
+ }
+
+ parser->last_node = node;
+
+ ++totalrrs;
+
+ return KNOTDZCOMPILE_EOK;
+}
+
+static uint find_rrsets_orphans(knot_zone_contents_t *zone, rrset_list_t
+ *head)
+{
+ uint found_rrsets = 0;
+ while (head != NULL) {
+ if (find_rrset_for_rrsig_in_zone(zone, head->data) == 0) {
+ found_rrsets += 1;
+ dbg_zp("RRSET succesfully found: owner %s type %s\n",
+ knot_dname_to_str(head->data->owner),
+ knot_rrtype_to_string(head->data->type));
+ }
+ else { /* we can throw it away now */
+ knot_rrset_free(&head->data);
+ }
+ head = head->next;
+ }
+ return found_rrsets;
+}
+
+/*
+ *
+ * Opens a zone file.
+ *
+ * Returns:
+ *
+ * - pointer to the parser structure
+ * - NULL on error and errno set
+ *
+ */
+static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass,
+ knot_node_t *origin, void *scanner, knot_dname_t *origin_from_config)
+{
+ /* Open the zone file... */
+ if (strcmp(filename, "-") == 0) {
+ zp_set_in(stdin, scanner);
+ filename = "<stdin>";
+ } else {
+ FILE *f = fopen(filename, "r");
+ if (f == NULL) {
+ return 0;
+ }
+ zp_set_in(f, scanner);
+ if (zp_get_in(scanner) == 0) {
+ return 0;
+ }
+ }
+
+// int fd = fileno(zp_get_in(scanner));
+// if (fd == -1) {
+// return 0;
+// }
+
+// if (fcntl(fd, F_SETLK, knot_file_lock(F_RDLCK, SEEK_SET)) == -1) {
+// fprintf(stderr, "Could not lock zone file for read!\n");
+// return 0;
+// }
+
+ zparser_init(filename, ttl, rclass, origin, origin_from_config);
+
+ return 1;
+}
+
+/*
+ * Reads the specified zone into the memory
+ *
+ */
+int zone_read(const char *name, const char *zonefile, const char *outfile,
+ int semantic_checks)
+{
+ if (!outfile) {
+ zc_error_prev_line("Missing output file for '%s'\n",
+ zonefile);
+ return KNOTDZCOMPILE_EINVAL;
+ }
+
+ /* Check that we can write to outfile. */
+ FILE *f = fopen(outfile, "wb");
+ if (f == NULL) {
+ fprintf(stderr, "Cannot write zone db to file '%s'\n",
+ outfile);
+ return KNOTDZCOMPILE_EINVAL;
+ }
+ fclose(f);
+
+
+// char ebuf[256];
+
+ knot_dname_t *dname =
+ knot_dname_new_from_str(name, strlen(name), NULL);
+ if (dname == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ knot_node_t *origin_node = knot_node_new(dname, NULL, 0);
+
+ /*!< \todo Another copy is probably not needed. */
+ knot_dname_t *origin_from_config =
+ knot_dname_new_from_str(name, strlen(name), NULL);
+ if (origin_from_config == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ //assert(origin_node->next == NULL);
+
+ assert(knot_node_parent(origin_node, 0) == NULL);
+ if (origin_node == NULL) {
+ knot_dname_release(dname);
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ void *scanner = NULL;
+ zp_lex_init(&scanner);
+ if (scanner == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ if (!zone_open(zonefile, 3600, KNOT_CLASS_IN, origin_node, scanner,
+ origin_from_config)) {
+ zc_error_prev_line("Cannot open '%s'\n",
+ zonefile);
+ zparser_free();
+ return KNOTDZCOMPILE_EZONEINVAL;
+ }
+
+ if (zp_parse(scanner) != 0) {
+// int fd = fileno(zp_get_in(scanner));
+// if (fcntl(fd, F_SETLK,
+// knot_file_lock(F_UNLCK, SEEK_SET)) == -1) {
+// return KNOTDZCOMPILE_EACCES;
+// }
+
+ FILE *in_file = (FILE *)zp_get_in(scanner);
+ fclose(in_file);
+ zp_lex_destroy(scanner);
+
+ return KNOTDZCOMPILE_ESYNT;
+ }
+
+ knot_zone_contents_t *contents =
+ knot_zone_get_contents(parser->current_zone);
+
+ FILE *in_file = (FILE *)zp_get_in(scanner);
+ fclose(in_file);
+ zp_lex_destroy(scanner);
+
+ /* Unlock zone file. */
+// int fd = fileno(zp_get_in(scanner));
+// if (fcntl(fd, F_SETLK, knot_file_lock(F_UNLCK, SEEK_SET)) == -1) {
+// fprintf(stderr, "Could not lock zone file for read!\n");
+// return 0;
+// }
+
+ dbg_zp("zp complete %p\n", parser->current_zone);
+
+ if (parser->last_node && parser->node_rrsigs != NULL) {
+ /* assign rrsigs to last node in the zone*/
+ process_rrsigs_in_node(contents,
+ parser->last_node);
+ rrset_list_delete(&parser->node_rrsigs);
+ }
+
+ dbg_zp("zone parsed\n");
+
+ if (!(parser->current_zone &&
+ knot_node_rrset(parser->current_zone->contents->apex,
+ KNOT_RRTYPE_SOA))) {
+ zc_error_prev_line("Zone file does not contain SOA record!\n");
+ knot_zone_deep_free(&parser->current_zone, 1);
+ zparser_free();
+ return KNOTDZCOMPILE_EZONEINVAL;
+ }
+
+ uint found_orphans;
+ found_orphans = find_rrsets_orphans(contents,
+ parser->rrsig_orphans);
+
+ dbg_zp("%u orphans found\n", found_orphans);
+
+ rrset_list_delete(&parser->rrsig_orphans);
+
+ if (found_orphans != parser->rrsig_orphan_count) {
+ fprintf(stderr,
+ "There are unassigned RRSIGs in the zone!\n");
+ parser->errors++;
+ }
+
+ knot_zone_contents_adjust(contents, 0);
+
+ dbg_zp("rdata adjusted\n");
+
+ if (parser->errors != 0) {
+ fprintf(stderr,
+ "Parser finished with error, not dumping the zone!\n");
+ } else {
+ if (knot_zdump_binary(contents,
+ outfile, semantic_checks,
+ zonefile) != 0) {
+ fprintf(stderr, "Could not dump zone!\n");
+ totalerrors++;
+ }
+ dbg_zp("zone dumped.\n");
+ }
+
+ /* This is *almost* unnecessary */
+ knot_zone_deep_free(&(parser->current_zone), 1);
+
+ fflush(stdout);
+ totalerrors += parser->errors;
+ zparser_free();
+
+ return totalerrors;
+}
+
+/*! @} */
diff --git a/src/zcompile/zcompile.h b/src/zcompile/zcompile.h
new file mode 100644
index 0000000..33dd3ee
--- /dev/null
+++ b/src/zcompile/zcompile.h
@@ -0,0 +1,207 @@
+/*!
+ * \file zoneparser.h
+ *
+ * \author modifications by Jan Kadlec <jan.kadlec@nic.cz>, most of the code
+ * by NLnet Labs.
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief Zone compiler.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KNOTD_ZONEPARSER_H_
+#define _KNOTD_ZONEPARSER_H_
+
+#include <stdio.h>
+
+#include "libknot/dname.h"
+#include "libknot/rrset.h"
+#include "libknot/zone/node.h"
+#include "libknot/rdata.h"
+#include "libknot/zone/zone.h"
+#include "libknot/zone/dname-table.h"
+#include "libknot/zone/dname-table.h"
+#include "common/slab/slab.h"
+
+#define MAXRDATALEN 64 /*!< Maximum number of RDATA items. */
+#define MAXLABELLEN 63 /*!< Maximum label length. */
+#define MAXDOMAINLEN 255 /*!< Maximum domain name length */
+#define MAX_RDLENGTH 65535 /*!< Maximum length of RDATA item */
+#define MAXTOKENSLEN 512 /*!< Maximum number of tokens per entry. */
+#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */
+#define ROOT (const uint8_t *)"\001" /*!< Root domain name. */
+
+#define NSEC_WINDOW_COUNT 256 /*!< Number of NSEC windows. */
+#define NSEC_WINDOW_BITS_COUNT 256 /*!< Number of bits in NSEC window. */
+/*! \brief Size of NSEC window in bytes. */
+#define NSEC_WINDOW_BITS_SIZE (NSEC_WINDOW_BITS_COUNT / 8)
+
+/*
+ * RFC 4025 - codes for different types that IPSECKEY can hold.
+ */
+#define IPSECKEY_NOGATEWAY 0
+#define IPSECKEY_IP4 1
+#define IPSECKEY_IP6 2
+#define IPSECKEY_DNAME 3
+
+#define LINEBUFSZ 1024 /*!< Buffer size for one line in zone file. */
+
+struct lex_data {
+ size_t len; /*!< holds the label length */
+ char *str; /*!< holds the data */
+};
+
+#define DEFAULT_TTL 3600
+
+int yylex_destroy(void *scanner);
+int zp_parse(void *scanner);
+void zp_set_in(FILE *f, void *scanner);
+int zp_lex_init(void **scanner);
+int zp_lex_destroy(void *scanner);
+
+/*! \todo Implement ZoneDB. */
+typedef void namedb_type;
+
+/*!
+ * \brief One-purpose linked list holding pointers to RRSets.
+ */
+struct rrset_list {
+ knot_rrset_t *data; /*!< List data. */
+ struct rrset_list *next; /*!< Next node. */
+};
+
+typedef struct rrset_list rrset_list_t;
+
+/*!
+ * \brief Main zoneparser structure.
+ */
+struct zparser {
+ const char *filename; /*!< File with zone. */
+ uint32_t default_ttl; /*!< Default TTL. */
+ uint16_t default_class; /*!< Default class. */
+ knot_zone_t *current_zone; /*!< Current zone. */
+ knot_node_t *origin; /*!< Origin node. */
+ knot_dname_t *prev_dname; /*!< Previous dname. */
+ knot_dname_t *origin_from_config; /*!< Zone origin from config. */
+ knot_node_t *default_apex; /*!< Zone default apex. */
+
+ knot_node_t *last_node; /*!< Last processed node. */
+
+ char *dname_str; /*!< Temporary dname. */
+
+ int error_occurred; /*!< Error occured flag */
+ unsigned int errors; /*!< Number of errors. */
+ unsigned int line; /*!< Current line */
+
+ knot_rrset_t *current_rrset; /*!< Current RRSet. */
+ knot_rdata_item_t *temporary_items; /*!< Temporary rdata items. */
+
+ /*!
+ * \brief list of RRSIGs that were not inside their nodes in zone file
+ */
+ rrset_list_t *rrsig_orphans;
+ unsigned long rrsig_orphan_count; /*!< RRSIG orphan count */
+
+ knot_dname_t *root_domain; /*!< Root domain name. */
+ slab_cache_t *parser_slab; /*!< Slab for parser. */
+ rrset_list_t *node_rrsigs; /*!< List of RRSIGs in current node. */
+
+ int rdata_count; /*!< Count of parsed rdata. */
+};
+
+typedef struct zparser zparser_type;
+
+extern zparser_type *parser;
+
+extern void zc_error_prev_line(const char *fmt, ...);
+
+/* used in zonec.lex */
+
+void zc_error_prev_line(const char *fmt, ...);
+void zc_warning_prev_line(const char *fmt, ...);
+
+/*!
+ * \brief Does all the processing of RR - saves to zone, assigns RRSIGs etc.
+ */
+int process_rr();
+
+/*!
+ * \brief Parses and creates zone from given file.
+ *
+ * \param name Origin domain name string.
+ * \param zonefile File containing the zone.
+ * \param outfile File to save dump of the zone to.
+ * \param semantic_checks Enables or disables sematic checks.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int zone_read(const char *name, const char *zonefile, const char *outfile,
+ int semantic_checks);
+
+/*!
+ * \brief Creates zparser instance.
+ *
+ *
+ * \return Created zparser instance.
+ */
+zparser_type *zparser_create();
+
+/*!
+ * \brief Inits zoneparser structure.
+ *
+ * \param filename Name of file with zone.
+ * \param ttl Default TTL.
+ * \param rclass Default class.
+ * \param origin Zone origin.
+ */
+void zparser_init(const char *filename, uint32_t ttl, uint16_t rclass,
+ knot_node_t *origin, knot_dname_t *owner_from_config);
+
+/*!
+ * \brief Frees zoneparser structure.
+ *
+ */
+void zparser_free();
+
+int save_dnames_in_table(knot_dname_table_t *table,
+ knot_rrset_t *rrset);
+
+#endif /* _KNOTD_ZONEPARSER_H_ */
+
+/*! @} */
diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c
new file mode 100644
index 0000000..cb862f8
--- /dev/null
+++ b/src/zcompile/zcompile_main.c
@@ -0,0 +1,116 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "zcompile/zcompile.h"
+#include "zcompile/zcompile-error.h"
+#include "common/errors.h"
+#include <config.h>
+
+static void help(int argc, char **argv)
+{
+ printf("Usage: %s [parameters] origin zonefile\n",
+ argv[0]);
+ printf("Parameters:\n"
+ " -o <outfile> Override output file.\n"
+ " -v Verbose mode - additional runtime information.\n"
+ " -s Enable semantic checks.\n"
+ " -V Print version of the server.\n"
+ " -h Print help and usage.\n");
+}
+
+int main(int argc, char **argv)
+{
+ // Parse command line arguments
+ int c = 0;
+ int verbose = 0;
+ int semantic_checks = 0;
+ const char* origin = 0;
+ const char* zonefile = 0;
+ const char* outfile = 0;
+ while ((c = getopt (argc, argv, "o:vVsh")) != -1) {
+ switch (c)
+ {
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'V':
+ printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION);
+ return 0;
+ case 's':
+ semantic_checks = 1;
+ break;
+ case 'h':
+ case '?':
+ default:
+ if (optopt == 'o') {
+ fprintf (stderr,
+ "Option -%c requires an argument.\n",
+ optopt);
+ }
+ help(argc, argv);
+ return 1;
+ }
+ }
+
+ UNUSED(verbose);
+
+ // Check if there's at least two remaining non-option
+ if (argc - optind < 2) {
+ help(argc, argv);
+ return 1;
+ }
+
+ origin = argv[optind];
+ zonefile = argv[optind + 1];
+
+ // Initialize log (no output)
+ //log_init(0);
+ //log_levels_set(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_DEBUG));
+
+ printf("Parsing file '%s', origin '%s' ...\n",
+ zonefile, origin);
+
+ parser = zparser_create();
+ if (!parser) {
+ fprintf(stderr, "Failed to create parser.\n");
+ //log_close();
+ return 1;
+ }
+
+ int error = zone_read(origin, zonefile, outfile, semantic_checks);
+
+ if (error) {
+ /* FIXME! */
+// if (error < 0) {
+// fprintf(stderr, "Finished with error: %s.\n",
+// error_to_str(knot_zcompile_error_msgs, error));
+// } else {
+// fprintf(stderr, "Finished with %u errors.\n");
+// }
+ } else {
+ printf("Compilation successful.\n");
+ }
+ //log_close();
+
+ return error;
+}
diff --git a/src/zcompile/zlexer.l b/src/zcompile/zlexer.l
new file mode 100644
index 0000000..c6c01fb
--- /dev/null
+++ b/src/zcompile/zlexer.l
@@ -0,0 +1,531 @@
+%{
+/*!
+ * \file zlexer.l
+ *
+ * \author minor modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * most of the code by NLnet Labs
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief lexical analyzer for (DNS) zone files.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#include "common.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <assert.h>
+
+#include "zcompile/zcompile.h"
+#include "libknot/dname.h"
+#include "zcompile/parser-descriptor.h"
+#include "zparser.h"
+
+#define YY_NO_INPUT
+
+/* Utils */
+extern void zc_error(const char *fmt, ...);
+extern void zc_warning(const char *fmt, ...);
+
+void strip_string(char *str)
+{
+ char *start = str;
+ char *end = str + strlen(str) - 1;
+
+ while (isspace(*start))
+ ++start;
+ if (start > end) {
+ /* Completely blank. */
+ str[0] = '\0';
+ } else {
+ while (isspace(*end))
+ --end;
+ *++end = '\0';
+
+ if (str != start)
+ memmove(str, start, end - start + 1);
+ }
+}
+
+int hexdigit_to_int(char ch)
+{
+ switch (ch) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': case 'A': return 10;
+ case 'b': case 'B': return 11;
+ case 'c': case 'C': return 12;
+ case 'd': case 'D': return 13;
+ case 'e': case 'E': return 14;
+ case 'f': case 'F': return 15;
+ default:
+ abort();
+ }
+}
+
+extern uint32_t strtottl(const char *nptr, const char **endptr);
+
+#define YY_NO_UNPUT
+#define MAXINCLUDES 10
+
+#define scanner yyscanner
+extern int zp_lex(YYSTYPE *lvalp, void *scanner);
+
+#if 0
+#define LEXOUT(s) printf s /* used ONLY when debugging */
+#else
+#define LEXOUT(s)
+#endif
+
+enum lexer_state {
+ EXPECT_OWNER,
+ PARSING_OWNER,
+ PARSING_TTL_CLASS_TYPE,
+ PARSING_RDATA
+};
+
+static YY_BUFFER_STATE include_stack[MAXINCLUDES];
+static zparser_type zparser_stack[MAXINCLUDES];
+static int include_stack_ptr = 0;
+
+static void pop_parser_state(void *scanner);
+static void push_parser_state(FILE *input, void *scanner);
+static int parse_token(void *scanner, int token, char *in_str,
+ enum lexer_state *lexer_state);
+
+
+/*!< \todo does not compile */
+#ifndef yy_set_bol // compat definition, for flex 2.4.6
+#define yy_set_bol(at_bol) \
+{ \
+ if (!yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \
+}
+#endif
+
+%}
+
+%option nounput
+%option reentrant bison-bridge
+%option prefix = "zp_"
+%option outfile = "lex.yy.c"
+
+SPACE [ \t]
+LETTER [a-zA-Z]
+NEWLINE [\n\r]
+ZONESTR [^ \t\n\r();.\"\$]
+DOLLAR \$
+COMMENT ;
+DOT \.
+BIT [^\]\n]|\\.
+ANY [^\"\n\\]|\\.
+
+%x incl bitlabel quotedstring
+
+%%
+ static int paren_open = 0;
+ static enum lexer_state lexer_state = EXPECT_OWNER;
+
+{SPACE}*{COMMENT}.* /* ignore */
+^{DOLLAR}TTL { lexer_state = PARSING_RDATA; return DOLLAR_TTL; }
+^{DOLLAR}ORIGIN { lexer_state = PARSING_RDATA; return DOLLAR_ORIGIN; }
+
+ /*
+ * Handle $INCLUDE directives. See
+ * http://dinosaur.compilertools.net/flex/flex_12.html#SEC12.
+ */
+^{DOLLAR}INCLUDE {
+ BEGIN(incl);
+}
+<incl>\n |
+<incl><<EOF>> {
+ int error_occurred = parser->error_occurred;
+ BEGIN(INITIAL);
+ zc_error("missing file name in $INCLUDE directive");
+ yy_set_bol(1); /* Set beginning of line, so "^" rules match. */
+ ++parser->line;
+ parser->error_occurred = error_occurred;
+}
+<incl>.+ {
+ char *tmp;
+ /*! \todo pointer to origin. */
+ void *origin = parser->origin;
+ /* domain_type *origin = parser->origin; */
+ int error_occurred = parser->error_occurred;
+
+ BEGIN(INITIAL);
+ if (include_stack_ptr >= MAXINCLUDES ) {
+ zc_error("includes nested too deeply, skipped (>%d)",
+ MAXINCLUDES);
+ } else {
+ FILE *input;
+
+ /* Remove trailing comment. */
+ tmp = strrchr(yytext, ';');
+ if (tmp) {
+ *tmp = '\0';
+ }
+ strip_string(yytext);
+
+ /* Parse origin for include file. */
+ tmp = strrchr(yytext, ' ');
+ if (!tmp) {
+ tmp = strrchr(yytext, '\t');
+ }
+ if (tmp) {
+ /* split the original yytext */
+ *tmp = '\0';
+ strip_string(yytext);
+
+ /*! \todo knot_dname_new_from_wire() (dname.h)
+ * which knot_node to pass as node?
+ */
+ knot_dname_t *dname;
+ dname = knot_dname_new_from_wire((uint8_t*)tmp + 1,
+ strlen(tmp + 1),
+ NULL);
+ if (!dname) {
+ zc_error("incorrect include origin '%s'",
+ tmp + 1);
+ } else {
+ /*! \todo insert to zonedb. */
+ /* origin = domain_table_insert(
+ parser->db->domains, dname); */
+ }
+ }
+
+ if (strlen(yytext) == 0) {
+ zc_error("missing file name in $INCLUDE directive");
+ } else if (!(input = fopen(yytext, "r"))) {
+ char ebuf[256];
+ zc_error("cannot open include file '%s': %s",
+ yytext, strerror_r(errno, ebuf, sizeof(ebuf)));
+ } else {
+ /* Initialize parser for include file. */
+ char *filename = strdup(yytext);
+ push_parser_state(input, scanner); /* Destroys yytext. */
+ parser->filename = filename;
+ parser->line = 1;
+ parser->origin = origin;
+ lexer_state = EXPECT_OWNER;
+ }
+ }
+
+ parser->error_occurred = error_occurred;
+}
+<INITIAL><<EOF>> {
+ yy_set_bol(1); /* Set beginning of line, so "^" rules match. */
+ if (include_stack_ptr == 0) {
+ // from: http://stackoverflow.com/questions/1756275/bison-end-of-file
+ static int once = 0;
+ once++;
+ if (once > 1) {
+ yyterminate();
+ } else {
+ return NL;
+ }
+ } else {
+ fclose(yyin);
+ pop_parser_state(scanner);
+ }
+}
+^{DOLLAR}{LETTER}+ { zc_warning("Unknown directive: %s", yytext); }
+{DOT} {
+ LEXOUT((". "));
+ return parse_token(scanner, '.', yytext, &lexer_state);
+}
+@ {
+ LEXOUT(("@ "));
+ return parse_token(scanner, '@', yytext, &lexer_state);
+}
+\\# {
+ LEXOUT(("\\# "));
+ return parse_token(scanner, URR, yytext, &lexer_state);
+}
+{NEWLINE} {
+ ++parser->line;
+ if (!paren_open) {
+ lexer_state = EXPECT_OWNER;
+ LEXOUT(("NL\n"));
+ return NL;
+ } else {
+ LEXOUT(("SP "));
+ return SP;
+ }
+}
+\( {
+ if (paren_open) {
+ zc_error("nested parentheses");
+ yyterminate();
+ }
+ LEXOUT(("( "));
+ paren_open = 1;
+ return SP;
+}
+\) {
+ if (!paren_open) {
+ zc_error("closing parentheses without opening parentheses");
+ yyterminate();
+ }
+ LEXOUT((") "));
+ paren_open = 0;
+ return SP;
+}
+{SPACE}+ {
+ if (!paren_open && lexer_state == EXPECT_OWNER) {
+ lexer_state = PARSING_TTL_CLASS_TYPE;
+ LEXOUT(("PREV "));
+ return PREV;
+ }
+ if (lexer_state == PARSING_OWNER) {
+ lexer_state = PARSING_TTL_CLASS_TYPE;
+ }
+ LEXOUT(("SP "));
+ return SP;
+}
+
+ /* Bitlabels. Strip leading and ending brackets. */
+\\\[ { BEGIN(bitlabel); }
+<bitlabel><<EOF>> {
+ zc_error("EOF inside bitlabel");
+ BEGIN(INITIAL);
+}
+<bitlabel>{BIT}* { yymore(); }
+<bitlabel>\n { ++parser->line; yymore(); }
+<bitlabel>\] {
+ BEGIN(INITIAL);
+ yytext[yyleng - 1] = '\0';
+ return parse_token(scanner, BITLAB, yytext, &lexer_state);
+}
+
+ /* Quoted strings. Strip leading and ending quotes. */
+\" { BEGIN(quotedstring); LEXOUT(("\" ")); }
+<quotedstring><<EOF>> {
+ zc_error("EOF inside quoted string");
+ BEGIN(INITIAL);
+}
+<quotedstring>{ANY}* { LEXOUT(("STR ")); yymore(); }
+<quotedstring>\n { ++parser->line; yymore(); }
+<quotedstring>\" {
+ LEXOUT(("\" "));
+ BEGIN(INITIAL);
+ yytext[yyleng - 1] = '\0';
+ return parse_token(scanner, STR, yytext, &lexer_state);
+}
+
+({ZONESTR}|\\.|\\\n)+ {
+ /* Any allowed word. */
+ return parse_token(scanner, STR, yytext, &lexer_state);
+}
+. {
+ zc_error("unknown character '%c' (\\%03d) seen - is this a zonefile?",
+ (int) yytext[0], (int) yytext[0]);
+}
+%%
+
+/*
+ * Analyze "word" to see if it matches an RR type, possibly by using
+ * the "TYPExxx" notation. If it matches, the corresponding token is
+ * returned and the TYPE parameter is set to the RR type value.
+ */
+static int
+rrtype_to_token(const char *word, uint16_t *type)
+{
+ uint16_t t = parser_rrtype_from_string(word);
+ if (t != 0) {
+ parser_rrtype_descriptor_t *entry = 0;
+ entry = parser_rrtype_descriptor_by_type(t);
+ *type = t;
+
+ /*! \todo entry should return associated token.
+ see nsd/dns.c */
+ return entry->token;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Remove \DDD constructs from the input. See RFC 1035, section 5.1.
+ */
+static size_t
+zoctet(char *text)
+{
+ /*
+ * s follows the string, p lags behind and rebuilds the new
+ * string
+ */
+ char *s;
+ char *p;
+
+ for (s = p = text; *s; ++s, ++p) {
+ assert(p <= s);
+ if (s[0] != '\\') {
+ /* Ordinary character. */
+ *p = *s;
+ } else if (isdigit((int)s[1]) && isdigit((int)s[2]) && isdigit((int)s[3])) {
+ /* \DDD escape. */
+ int val = (hexdigit_to_int(s[1]) * 100 +
+ hexdigit_to_int(s[2]) * 10 +
+ hexdigit_to_int(s[3]));
+ if (0 <= val && val <= 255) {
+ s += 3;
+ *p = val;
+ } else {
+ zc_warning("text escape \\DDD overflow");
+ *p = *++s;
+ }
+ } else if (s[1] != '\0') {
+ /* \X where X is any character, keep X. */
+ *p = *++s;
+ } else {
+ /* Trailing backslash, ignore it. */
+ zc_warning("trailing backslash ignored");
+ --p;
+ }
+ }
+ *p = '\0';
+ return p - text;
+}
+
+static int parse_token(void *scanner, int token, char *in_str,
+ enum lexer_state *lexer_state)
+{
+ size_t len = 0;
+ char *str = NULL;
+
+ struct yyguts_t *yyg = (struct yyguts_t *)scanner;
+
+ if (*lexer_state == EXPECT_OWNER) {
+ *lexer_state = PARSING_OWNER;
+ } else if (*lexer_state == PARSING_TTL_CLASS_TYPE) {
+ const char *t;
+ int token;
+ uint16_t rrclass;
+
+ /* type */
+ token = rrtype_to_token(in_str, &yylval->type);
+ if (token != 0) {
+ *lexer_state = PARSING_RDATA;
+ LEXOUT(("%d[%s] ", token, in_str));
+ return token;
+ }
+
+ /* class */
+ rrclass = parser_rrclass_from_string(in_str);
+ if (rrclass != 0) {
+ yylval->rclass = rrclass;
+ LEXOUT(("CLASS "));
+ return T_RRCLASS;
+ }
+
+ /* ttl */
+ yylval->ttl = strtottl(in_str, &t);
+ if (*t == '\0') {
+ LEXOUT(("TTL "));
+ return T_TTL;
+ }
+ }
+
+ str = strdup(yytext);
+ if (str == NULL) {
+ /* Out of memory */
+ ERR_ALLOC_FAILED;
+ return NO_MEM;
+ }
+ len = zoctet(str);
+
+ yylval->data.str = str;
+ assert(yylval->data.str != NULL);
+ yylval->data.len = len;
+
+ if (strcmp(yytext, ".") == 0) {
+ free(str);
+ yylval->data.str=".";
+ } else if (strcmp(str, "@") == 0) {
+ free(str);
+ yylval->data.str="@";
+ } else if (strcmp(str, "\\#") == 0) {
+ free(str);
+ yylval->data.str="\\#";
+ }
+
+ LEXOUT(("%d[%s] ", token, in_str));
+ return token;
+}
+
+/*
+ * Saves the file specific variables on the include stack.
+ */
+static void push_parser_state(FILE *input, void *scanner)
+{
+ struct yyguts_t *yyg = (struct yyguts_t *)scanner;
+ zparser_stack[include_stack_ptr].filename = parser->filename;
+ zparser_stack[include_stack_ptr].line = parser->line;
+ zparser_stack[include_stack_ptr].origin = parser->origin;
+ include_stack[include_stack_ptr] = YY_CURRENT_BUFFER;
+ yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE, scanner),
+ scanner);
+ ++include_stack_ptr;
+}
+
+/*
+ * Restores the file specific variables from the include stack.
+ */
+void pop_parser_state(void *scanner)
+{
+ struct yyguts_t *yyg = (struct yyguts_t *)scanner;
+ --include_stack_ptr;
+ parser->filename = zparser_stack[include_stack_ptr].filename;
+ parser->line = zparser_stack[include_stack_ptr].line;
+ parser->origin = zparser_stack[include_stack_ptr].origin;
+ yy_delete_buffer(YY_CURRENT_BUFFER, scanner);
+ yy_switch_to_buffer(include_stack[include_stack_ptr], scanner);
+}
diff --git a/src/zcompile/zparser.y b/src/zcompile/zparser.y
new file mode 100644
index 0000000..6f081e5
--- /dev/null
+++ b/src/zcompile/zparser.y
@@ -0,0 +1,1730 @@
+%{
+/*!
+ * \file zparser.y
+ *
+ * \author modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * notable changes: normal allocation, parser is reentrant.
+ * most of the code by NLnet Labs
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief yacc grammar for (DNS) zone files
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#include "common.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "zcompile/parser-util.h"
+
+#include "libknot/libknot.h"
+#include "zcompile/zcompile.h"
+#include "zcompile/parser-descriptor.h"
+#include "zcompile/zcompile-error.h"
+#include "zparser.h"
+
+/* these need to be global, otherwise they cannot be used inside yacc */
+zparser_type *parser;
+
+#ifdef __cplusplus
+extern "C"
+#endif /* __cplusplus */
+int zp_wrap(void);
+
+/* this hold the nxt bits */
+static uint8_t nxtbits[16];
+static int dlv_warn = 1;
+
+/* 256 windows of 256 bits (32 bytes) */
+/* still need to reset the bastard somewhere */
+static uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE];
+
+/* hold the highest rcode seen in a NSEC rdata , BUG #106 */
+uint16_t nsec_highest_rcode;
+
+void zp_error(void *scanner, const char *message);
+int zp_lex(YYSTYPE *lvalp, void *scanner);
+
+/* helper functions */
+void zc_error(const char *fmt, ...);
+void zc_warning(const char *fmt, ...);
+void zc_error_prev_line(const char *fmt, ...);
+void zc_warning_prev_line(const char *fmt, ...);
+
+#define NSEC3
+#ifdef NSEC3
+/* parse nsec3 parameters and add the (first) rdata elements */
+static void
+nsec3_add_params(const char* hash_algo_str, const char* flag_str,
+ const char* iter_str, const char* salt_str, int salt_len);
+#endif /* NSEC3 */
+
+knot_dname_t *error_dname; //XXX used to be const
+knot_dname_t *error_domain;
+
+%}
+%union {
+ knot_dname_t *domain;
+ knot_dname_t *dname;
+ struct lex_data data;
+ uint32_t ttl;
+ uint16_t rclass;
+ uint16_t type;
+ uint16_t *unknown;
+}
+
+%pure-parser
+%parse-param {void *scanner}
+%lex-param {void *scanner}
+%name-prefix = "zp_"
+
+/*
+ * Tokens to represent the known RR types of DNS.
+ */
+%token <type> T_A T_NS T_MX T_TXT T_CNAME T_AAAA T_PTR T_NXT T_KEY T_SOA T_SIG
+%token <type> T_SRV T_CERT T_LOC T_MD T_MF T_MB T_MG T_MR T_NULL T_WKS T_HINFO
+%token <type> T_MINFO T_RP T_AFSDB T_X25 T_ISDN T_RT T_NSAP T_NSAP_PTR T_PX
+%token <type> T_GPOS T_EID T_NIMLOC T_ATMA T_NAPTR T_KX T_A6 T_DNAME T_SINK
+%token <type> T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR
+%token <type> T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY
+%token <type> T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM
+
+/* other tokens */
+%token DOLLAR_TTL DOLLAR_ORIGIN NL SP NO_MEM
+%token <data> STR PREV BITLAB
+%token <ttl> T_TTL
+%token <rclass> T_RRCLASS
+
+/* unknown RRs */
+%token URR
+%token <type> T_UTYPE
+
+%type <type> type_and_rdata
+%type <domain> owner dname abs_dname
+%type <dname> rel_dname label
+%type <data> wire_dname wire_abs_dname wire_rel_dname wire_label
+%type <data> concatenated_str_seq str_sp_seq str_dot_seq dotted_str
+%type <data> nxt_seq nsec_more
+%type <unknown> rdata_unknown
+
+%%
+lines: /* empty file */
+ | lines line
+ ;
+
+line: NL
+ | sp NL
+ | NO_MEM {
+ zc_error_prev_line("Parser ran out of memory!");
+ YYABORT;
+ }
+ | PREV NL {} /* Lines containing only whitespace. */
+ | ttl_directive
+ {
+ parser->error_occurred = 0;
+ }
+ | origin_directive
+ {
+ parser->error_occurred = 0;
+ }
+ | rr
+ { /* rr should be fully parsed */
+ if (!parser->error_occurred) {
+ /*!< \todo assign error to error occurred */
+ /*! \todo Make sure this does not crash */
+ if (parser->current_rrset->owner == NULL) {
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ knot_rdata_t *tmp_rdata = knot_rdata_new();
+ if (tmp_rdata == NULL) {
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+
+ if (knot_rdata_set_items(tmp_rdata,
+ parser->temporary_items,
+ parser->rdata_count) != 0) {
+ knot_rdata_free(&tmp_rdata);
+ knot_rrset_deep_free(&(parser->current_rrset), 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone), 1);
+ YYABORT;
+ }
+
+ assert(parser->current_rrset->rdata == NULL);
+ if (knot_rrset_add_rdata(parser->current_rrset, tmp_rdata)
+ != 0) {
+ fprintf(stderr, "Could not add rdata!\n");
+ }
+// tmp_rdata->next = tmp_rdata;
+// parser->current_rrset->rdata = tmp_rdata;
+
+ if (!knot_dname_is_fqdn(parser->current_rrset->owner)) {
+ knot_dname_t *tmp_dname =
+ knot_dname_cat(parser->current_rrset->owner,
+ parser->root_domain);
+ if (tmp_dname == NULL) {
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+// knot_rrset_set_owner(parser->current_rrset, tmp_dname);
+ }
+
+ assert(parser->current_rrset->owner != NULL);
+ knot_dname_retain(parser->current_rrset->owner);
+ int ret = 0;
+ if ((ret = process_rr()) != 0) {
+ char *name =
+ knot_dname_to_str(parser->current_rrset->owner);
+ fprintf(stderr, "Error: could not process RRSet\n"
+ "owner: %s reason: %s\n",
+ name,
+ error_to_str(knot_zcompile_error_msgs, ret));
+ free(name);
+
+ /* If the owner is not already in the table, free it. */
+// if (dnslib_dname_table_find_dname(parser->dname_table,
+// parser->current_rrset->owner) == NULL) {
+// dnslib_dname_free(&parser->
+// current_rrset->owner);
+// } /* This would never happen */
+
+ if (ret == KNOTDZCOMPILE_EBADSOA) {
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ } else {
+ YYABORT;
+ /* Free rdata, it will not be added
+ * and hence cannot be
+ * freed with rest of the zone. */
+/* knot_rdata_deep_free(&tmp_rdata,
+ parser->
+ current_rrset->type,
+ 0); */
+ }
+ }
+ } else {
+ /* Error occured. This could either be lack of memory, or one
+ * of the converting function was not able to convert. */
+ if (parser->error_occurred == KNOTDZCOMPILE_ENOMEM) {
+ /* Ran out of memory in converting functions. */
+ fprintf(stderr, "Parser ran out "
+ "of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ }
+
+// printf("Current rrset name: %p (%s)\n", parser->current_rrset->owner->name,
+// knot_dname_to_str(parser->current_rrset->owner));
+// getchar();
+
+// knot_dname_release(parser->current_rrset->owner);
+
+ parser->current_rrset->type = 0;
+ parser->rdata_count = 0;
+ parser->current_rrset->rdata = NULL;
+ parser->error_occurred = 0;
+ }
+ | error NL
+ ;
+
+/* needed to cope with ( and ) in arbitary places */
+sp: SP
+ | sp SP
+ ;
+
+trail: NL
+ | sp NL
+ ;
+
+ttl_directive: DOLLAR_TTL sp STR trail
+ {
+ parser->default_ttl = zparser_ttl2int($3.str,
+ &(parser->error_occurred));
+ if (parser->error_occurred == 1) {
+ parser->default_ttl = DEFAULT_TTL;
+ parser->error_occurred = 0;
+ }
+
+ free($3.str);
+ }
+ ;
+
+
+
+origin_directive: DOLLAR_ORIGIN sp abs_dname trail
+ {
+ knot_node_t *origin_node = knot_node_new($3 ,NULL, 0);
+ if (parser->origin != NULL) {
+// knot_node_free(&parser->origin, 1);
+ }
+ parser->origin = origin_node;
+ }
+ | DOLLAR_ORIGIN sp rel_dname trail
+ {
+ zc_error_prev_line("$ORIGIN directive requires"
+ "absolute domain name");
+ }
+ ;
+
+rr: owner classttl type_and_rdata
+ {
+ /* Save the pointer, it might get freed! */
+ parser->current_rrset->owner = $1;
+// parser->current_rrset->owner = $1;
+// printf("new owner assigned: %p\n", $1);
+ parser->current_rrset->type = $3;
+ }
+ ;
+
+owner: dname sp
+ {
+// char *name = knot_dname_to_str($1);
+// printf("Totally new dname: %p %s\n", $1,
+// name);
+// free(name);
+ if (parser->prev_dname != NULL) {
+ // knot_dname_release(parser->prev_dname);
+ }
+ parser->prev_dname = $1;//knot_dname_deep_copy($1);
+// knot_dname_retain(parser->prev_dname);
+ $$ = $1;
+ }
+ | PREV
+ {
+// printf("Name from prev_dname!: %p %s\n", parser->prev_dname,
+// knot_dname_to_str(parser->prev_dname));
+ knot_dname_retain(parser->prev_dname);
+ $$ = parser->prev_dname;//knot_dname_deep_copy(parser->prev_dname);
+ }
+ ;
+
+classttl: /* empty - fill in the default, def. ttl and IN class */
+ {
+ parser->current_rrset->ttl = parser->default_ttl;
+ parser->current_rrset->rclass = parser->default_class;
+ }
+ | T_RRCLASS sp /* no ttl */
+ {
+ parser->current_rrset->ttl = parser->default_ttl;
+ parser->current_rrset->rclass = $1;
+ }
+ | T_TTL sp /* no class */
+ {
+ parser->current_rrset->ttl = $1;
+ parser->current_rrset->rclass = parser->default_class;
+ }
+ | T_TTL sp T_RRCLASS sp /* the lot */
+ {
+ parser->current_rrset->ttl = $1;
+ parser->current_rrset->rclass = $3;
+ }
+ | T_RRCLASS sp T_TTL sp /* the lot - reversed */
+ {
+ parser->current_rrset->ttl = $3;
+ parser->current_rrset->rclass = $1;
+ }
+ ;
+
+dname: abs_dname
+ | rel_dname
+ {
+ if ($1 == error_dname) {
+ $$ = error_domain;
+ } else if ($1->size + parser->origin->owner->size - 1 >
+ MAXDOMAINLEN) {
+ zc_error("domain name exceeds %d character limit",
+ MAXDOMAINLEN);
+ $$ = error_domain;
+ } else {
+ $$ = knot_dname_cat($1,
+ parser->origin->owner);
+// printf("leak: %s\n", knot_dname_to_str($$));
+// getchar();
+ }
+ }
+ ;
+
+abs_dname: '.'
+ {
+ $$ = parser->root_domain;
+ /* TODO how about concatenation now? */
+ }
+ | '@'
+ {
+ $$ = parser->origin->owner;
+ }
+ | rel_dname '.'
+ {
+ if ($1 != error_dname) {
+ $$ = $1;
+ } else {
+ $$ = error_domain;
+ }
+ }
+ ;
+
+label: STR
+ {
+ if ($1.len > MAXLABELLEN) {
+ zc_error("label exceeds %d character limit", MAXLABELLEN);
+ $$ = error_dname;
+ } else {
+// printf("%s\n", $1.str);
+ $$ = knot_dname_new_from_str($1.str, $1.len, NULL);
+// printf("Creating new (label): %s %p\n", $1.str, $$);
+// printf("new: %p %s\n", $$, $1.str);
+ $$->ref.count = 0;
+ }
+
+ free($1.str);
+
+ }
+ | BITLAB
+ {
+ zc_error("bitlabels are not supported."
+ "RFC2673 has status experimental.");
+ $$ = error_dname;
+ }
+ ;
+
+rel_dname: label
+ | rel_dname '.' label
+ {
+ if ($1 == error_dname || $3 == error_dname) {
+ $$ = error_dname;
+ } else if ($1->size + $3->size - 1 > MAXDOMAINLEN) {
+ zc_error("domain name exceeds %d character limit",
+ MAXDOMAINLEN);
+ $$ = error_dname;
+ } else {
+ $$ = knot_dname_cat($1, $3);
+// knot_dname_release($1); /*!< \todo check! */
+ knot_dname_free(&$3);
+ }
+ }
+ ;
+
+/*
+ * Some dnames in rdata are handled as opaque blobs
+ */
+
+wire_dname: wire_abs_dname
+ | wire_rel_dname
+ ;
+
+wire_abs_dname: '.'
+ {
+ char *result = malloc(2 * sizeof(char));
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ result[0] = 0;
+ result[1] = '\0';
+ $$.str = result;
+ $$.len = 1;
+ }
+ | wire_rel_dname '.'
+ {
+ char *result = malloc($1.len + 2 * sizeof(char));
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ result[$1.len] = 0;
+ result[$1.len+1] = '\0';
+ $$.str = result;
+ $$.len = $1.len + 1;
+
+ free($1.str);
+;
+ }
+ ;
+
+wire_label: STR
+ {
+ char *result = malloc($1.len + sizeof(char));
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+
+ if ($1.len > MAXLABELLEN)
+ zc_error("label exceeds %d character limit", MAXLABELLEN);
+
+ /* make label anyway */
+ result[0] = $1.len;
+ memcpy(result+1, $1.str, $1.len);
+
+ $$.str = result;
+ $$.len = $1.len + 1;
+
+ free($1.str);
+ }
+ ;
+
+wire_rel_dname: wire_label
+ | wire_rel_dname '.' wire_label
+ {
+ if ($1.len + $3.len - 3 > MAXDOMAINLEN)
+ zc_error("domain name exceeds %d character limit",
+ MAXDOMAINLEN);
+
+ /* make dname anyway */
+ $$.len = $1.len + $3.len;
+ $$.str = malloc($$.len + sizeof(char));
+ if ($$.str == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy($$.str, $1.str, $1.len);
+ memcpy($$.str + $1.len, $3.str, $3.len);
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+
+
+str_seq: STR
+ {
+ zadd_rdata_txt_wireformat(zparser_conv_text($1.str, $1.len), 1);
+
+ free($1.str);
+ }
+ | str_seq sp STR
+ {
+ zadd_rdata_txt_wireformat(zparser_conv_text($3.str, $3.len), 0);
+// zc_warning("multiple TXT entries are currently not supported!");
+
+ free($3.str);
+ }
+ ;
+
+/*
+ * Generate a single string from multiple STR tokens, separated by
+ * spaces or dots.
+ */
+concatenated_str_seq: STR
+ | '.'
+ {
+ $$.len = 1;
+ $$.str = strdup(".");
+ }
+ | concatenated_str_seq sp STR
+ {
+ $$.len = $1.len + $3.len + 1;
+ $$.str = malloc($$.len + 1);
+ if ($$.str == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+
+ memcpy($$.str, $1.str, $1.len);
+ memcpy($$.str + $1.len, " ", 1);
+ memcpy($$.str + $1.len + 1, $3.str, $3.len);
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ free($3.str);
+ }
+ | concatenated_str_seq '.' STR
+ {
+ $$.len = $1.len + $3.len + 1;
+ $$.str = malloc($$.len + 1);
+ if ($$.str == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy($$.str, $1.str, $1.len);
+ memcpy($$.str + $1.len, ".", 1);
+ memcpy($$.str + $1.len + 1, $3.str, $3.len);
+
+ free($1.str);
+ free($3.str);
+
+ $$.str[$$.len] = '\0';
+ }
+ ;
+
+/* used to convert a nxt list of types */
+nxt_seq: STR
+ {
+ uint16_t type = knot_rrtype_from_string($1.str);
+ if (type != 0 && type < 128) {
+ set_bit(nxtbits, type);
+ } else {
+ zc_error("bad type %d in NXT record", (int) type);
+ }
+
+ free($1.str);
+ }
+ | nxt_seq sp STR
+ {
+ uint16_t type = knot_rrtype_from_string($3.str);
+ if (type != 0 && type < 128) {
+ set_bit(nxtbits, type);
+ } else {
+ zc_error("bad type %d in NXT record", (int) type);
+ }
+
+ free($3.str);
+ }
+ ;
+
+nsec_more: SP nsec_more
+ {
+ }
+ | NL
+ {
+ }
+ | STR nsec_seq
+ {
+ uint16_t type = knot_rrtype_from_string($1.str);
+ if (type != 0) {
+ if (type > nsec_highest_rcode) {
+ nsec_highest_rcode = type;
+ }
+ set_bitnsec(nsecbits, type);
+ } else {
+ zc_error("bad type %d in NSEC record", (int) type);
+ }
+
+ free($1.str);
+ }
+ ;
+
+nsec_seq: NL
+ | SP nsec_more
+ ;
+
+/*
+ * Sequence of STR tokens separated by spaces. The spaces are not
+ * preserved during concatenation.
+ */
+str_sp_seq: STR
+ | str_sp_seq sp STR
+ {
+ char *result = malloc($1.len + $3.len + 1);
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ fprintf(stderr, "Parser ran out of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ memcpy(result + $1.len, $3.str, $3.len);
+ $$.str = result;
+ $$.len = $1.len + $3.len;
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+/*
+ * Sequence of STR tokens separated by dots. The dots are not
+ * preserved during concatenation.
+ */
+str_dot_seq: STR
+ | str_dot_seq '.' STR
+ {
+ char *result = malloc($1.len + $3.len + 1);
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ fprintf(stderr, "Parser ran out of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ memcpy(result + $1.len, $3.str, $3.len);
+ $$.str = result;
+ $$.len = $1.len + $3.len;
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+/*
+ * A string that can contain dots.
+ */
+dotted_str: STR
+ | '.'
+ {
+ $$.str = ".";
+ $$.len = 1;
+ }
+ | dotted_str '.'
+ {
+ char *result = malloc($1.len + 2);
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ fprintf(stderr, "Parser ran out of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ result[$1.len] = '.';
+ $$.str = result;
+ $$.len = $1.len + 1;
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ }
+ | dotted_str '.' STR
+ {
+ char *result = malloc($1.len + $3.len + 2);
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ fprintf(stderr, "Parser ran out of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ result[$1.len] = '.';
+ memcpy(result + $1.len + 1, $3.str, $3.len);
+ $$.str = result;
+ $$.len = $1.len + $3.len + 1;
+ $$.str[$$.len] = '\0';
+
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+/* define what we can parse */
+type_and_rdata:
+ /*
+ * All supported RR types. We don't support NULL and types marked obsolete.
+ */
+ T_A sp rdata_a
+ | T_A sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_NS sp rdata_domain_name
+ | T_NS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_MD sp rdata_domain_name { zc_warning_prev_line("MD is obsolete"); }
+ | T_MD sp rdata_unknown
+ {
+ zc_warning_prev_line("MD is obsolete");
+ $$ = $1; parse_unknown_rdata($1, $3);
+ }
+ | T_MF sp rdata_domain_name { zc_warning_prev_line("MF is obsolete"); }
+ | T_MF sp rdata_unknown
+ {
+ zc_warning_prev_line("MF is obsolete");
+ $$ = $1;
+ parse_unknown_rdata($1, $3);
+ }
+ | T_CNAME sp rdata_domain_name
+ | T_CNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_SOA sp rdata_soa
+ | T_SOA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_MB sp rdata_domain_name { zc_warning_prev_line("MB is obsolete"); }
+ | T_MB sp rdata_unknown
+ {
+ zc_warning_prev_line("MB is obsolete");
+ $$ = $1;
+ parse_unknown_rdata($1, $3);
+ }
+ | T_MG sp rdata_domain_name
+ | T_MG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_MR sp rdata_domain_name
+ | T_MR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ /* NULL */
+ | T_WKS sp rdata_wks
+ | T_WKS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_PTR sp rdata_domain_name
+ | T_PTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_HINFO sp rdata_hinfo
+ | T_HINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_MINFO sp rdata_minfo /* Experimental */
+ | T_MINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_MX sp rdata_mx
+ | T_MX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_TXT sp rdata_txt
+ | T_TXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_SPF sp rdata_txt
+ | T_SPF sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_RP sp rdata_rp /* RFC 1183 */
+ | T_RP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_AFSDB sp rdata_afsdb /* RFC 1183 */
+ | T_AFSDB sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_X25 sp rdata_x25 /* RFC 1183 */
+ | T_X25 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_ISDN sp rdata_isdn /* RFC 1183 */
+ | T_ISDN sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_IPSECKEY sp rdata_ipseckey /* RFC 4025 */
+ | T_IPSECKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_DHCID sp rdata_dhcid
+ | T_DHCID sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_RT sp rdata_rt /* RFC 1183 */
+ | T_RT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_NSAP sp rdata_nsap /* RFC 1706 */
+ | T_NSAP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_SIG sp rdata_rrsig
+ | T_SIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_KEY sp rdata_dnskey
+ | T_KEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_PX sp rdata_px /* RFC 2163 */
+ | T_PX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_AAAA sp rdata_aaaa
+ | T_AAAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_LOC sp rdata_loc
+ | T_LOC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_NXT sp rdata_nxt
+ | T_NXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_SRV sp rdata_srv
+ | T_SRV sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_NAPTR sp rdata_naptr /* RFC 2915 */
+ | T_NAPTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_KX sp rdata_kx /* RFC 2230 */
+ | T_KX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_CERT sp rdata_cert /* RFC 2538 */
+ | T_CERT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_DNAME sp rdata_domain_name /* RFC 2672 */
+ | T_DNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_APL trail /* RFC 3123 */
+ | T_APL sp rdata_apl /* RFC 3123 */
+ | T_APL sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_DS sp rdata_ds
+ | T_DS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_DLV sp rdata_dlv
+ {
+ if (dlv_warn) {
+ dlv_warn = 0;
+ zc_warning_prev_line("DLV is experimental");
+ }
+ }
+ | T_DLV sp rdata_unknown
+ {
+ if (dlv_warn) {
+ dlv_warn = 0;
+ zc_warning_prev_line("DLV is experimental");
+ }
+ $$ = $1;
+ parse_unknown_rdata($1, $3);
+ }
+ | T_SSHFP sp rdata_sshfp
+ | T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_RRSIG sp rdata_rrsig
+ | T_RRSIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_NSEC sp rdata_nsec
+ | T_NSEC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_NSEC3 sp rdata_nsec3
+ | T_NSEC3 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_NSEC3PARAM sp rdata_nsec3_param
+ | T_NSEC3PARAM sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_DNSKEY sp rdata_dnskey
+ | T_DNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+ | T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+
+ | STR error NL
+ {
+ zc_error_prev_line("unrecognized RR type '%s'", $1.str);
+ free($1.str);
+ }
+ | NO_MEM
+ {
+ zc_error_prev_line("parser ran out of memory!");
+ YYABORT;
+ }
+ ;
+
+/*
+ *
+ * below are all the definition for all the different rdata
+ *
+ */
+
+rdata_a: dotted_str trail
+ {
+ zadd_rdata_wireformat(zparser_conv_a($1.str));
+ free($1.str);
+ }
+ ;
+
+rdata_domain_name: dname trail
+ {
+ /* convert a single dname record */
+ if ($1 != NULL) {
+ if (!knot_dname_is_fqdn($1)) {
+ knot_dname_cat($1, parser->root_domain);
+// parser->current_rrset->owner =
+// knot_dname_cat($1, parser->root_domain);
+ }
+ }
+ zadd_rdata_domain($1);
+ }
+ ;
+
+rdata_soa: dname sp dname sp STR sp STR sp STR sp STR sp STR trail
+ {
+ /* convert the soa data */
+ if (!knot_dname_is_fqdn($1)) {
+ knot_dname_cat($1, parser->root_domain);
+// parser->current_rrset->owner =
+// knot_dname_cat($1, parser->root_domain);
+
+ }
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+// parser->current_rrset->owner =
+// knot_dname_cat($3, parser->root_domain);
+
+ }
+ zadd_rdata_domain($1); /* prim. ns */
+ zadd_rdata_domain($3); /* email */
+ zadd_rdata_wireformat(zparser_conv_serial($5.str)); /* serial */
+ zadd_rdata_wireformat(zparser_conv_period($7.str)); /* refresh */
+ zadd_rdata_wireformat(zparser_conv_period($9.str)); /* retry */
+ zadd_rdata_wireformat(zparser_conv_period($11.str)); /* expire */
+ zadd_rdata_wireformat(zparser_conv_period($13.str)); /* minimum */
+
+ free($5.str);
+ free($7.str);
+ free($9.str);
+ free($11.str);
+ free($13.str);
+ }
+ ;
+
+rdata_wks: dotted_str sp STR sp concatenated_str_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_a($1.str)); /* address */
+ zadd_rdata_wireformat(zparser_conv_services($3.str, $5.str));
+ /* protocol and services */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ }
+ ;
+
+rdata_hinfo: STR sp STR trail
+ {
+ zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len)); /* CPU */
+ zadd_rdata_wireformat(zparser_conv_text($3.str, $3.len)); /* OS*/
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+rdata_minfo: dname sp dname trail
+ {
+ if (!knot_dname_is_fqdn($1)) {
+
+ knot_dname_cat($1, parser->root_domain);
+
+ }
+ if (!knot_dname_is_fqdn($3)) {
+
+ knot_dname_cat($3, parser->root_domain);
+
+ }
+
+ /* convert a single dname record */
+ zadd_rdata_domain($1);
+ zadd_rdata_domain($3);
+ }
+ ;
+
+rdata_mx: STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* priority */
+ zadd_rdata_domain($3); /* MX host */
+
+ free($1.str);
+ }
+ ;
+
+rdata_txt: str_seq trail
+ {
+ ; //zadd_rdata_txt_clean_wireformat();
+ }
+ ;
+
+/* RFC 1183 */
+rdata_rp: dname sp dname trail
+ {
+ if (!knot_dname_is_fqdn($1)) {
+ knot_dname_cat($1, parser->root_domain);
+ }
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+
+ zadd_rdata_domain($1); /* mbox d-name */
+ zadd_rdata_domain($3); /* txt d-name */
+ }
+ ;
+
+/* RFC 1183 */
+rdata_afsdb: STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* subtype */
+ zadd_rdata_domain($3); /* domain name */
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 1183 */
+rdata_x25: STR trail
+ {
+ zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len));
+ /* X.25 address. */
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 1183 */
+rdata_isdn: STR trail
+ {
+ zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len));
+ /* address */
+
+ free($1.str);
+ }
+ | STR sp STR trail
+ {
+ zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len));
+ /* address */
+ zadd_rdata_wireformat(zparser_conv_text($3.str, $3.len));
+ /* sub-address */
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+/* RFC 1183 */
+rdata_rt: STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */
+ zadd_rdata_domain($3); /* intermediate host */
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 1706 */
+rdata_nsap: str_dot_seq trail
+ {
+ /* String must start with "0x" or "0X". */
+ if (strncasecmp($1.str, "0x", 2) != 0) {
+ zc_error_prev_line("NSAP rdata must start with '0x'");
+ } else {
+ zadd_rdata_wireformat(zparser_conv_hex($1.str + 2,
+ $1.len - 2));
+ /* NSAP */
+ }
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 2163 */
+rdata_px: STR sp dname sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+ if (!knot_dname_is_fqdn($5)) {
+ knot_dname_cat($5, parser->root_domain);
+ }
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */
+ zadd_rdata_domain($3); /* MAP822 */
+ zadd_rdata_domain($5); /* MAPX400 */
+
+ free($1.str);
+ }
+ ;
+
+rdata_aaaa: dotted_str trail
+ {
+ zadd_rdata_wireformat(zparser_conv_aaaa($1.str));
+ /* IPv6 address */
+
+ free($1.str);
+ }
+ ;
+
+rdata_loc: concatenated_str_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_loc($1.str)); /* Location */
+
+ free($1.str);
+ }
+ ;
+
+rdata_nxt: dname sp nxt_seq trail
+ {
+ if (!knot_dname_is_fqdn($1)) {
+ knot_dname_cat($1, parser->root_domain);
+ }
+ zadd_rdata_domain($1); /* nxt name */
+ zadd_rdata_wireformat(zparser_conv_nxt(nxtbits)); /* nxt bitlist */
+ memset(nxtbits, 0, sizeof(nxtbits));
+ }
+ ;
+
+rdata_srv: STR sp STR sp STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($7)) {
+ knot_dname_cat($7, parser->root_domain);
+
+ }
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* prio */
+ zadd_rdata_wireformat(zparser_conv_short($3.str)); /* weight */
+ zadd_rdata_wireformat(zparser_conv_short($5.str)); /* port */
+ zadd_rdata_domain($7); /* target name */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ }
+ ;
+
+/* RFC 2915 */
+rdata_naptr: STR sp STR sp STR sp STR sp STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($11)) {
+ knot_dname_cat($11, parser->root_domain);
+
+ }
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* order */
+ zadd_rdata_wireformat(zparser_conv_short($3.str)); /* preference */
+ zadd_rdata_wireformat(zparser_conv_text($5.str, $5.len));
+ /* flags */
+ zadd_rdata_wireformat(zparser_conv_text($7.str, $7.len));
+ /* service */
+ zadd_rdata_wireformat(zparser_conv_text($9.str, $9.len));
+ /* regexp */
+ zadd_rdata_domain($11); /* target name */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ free($9.str);
+ }
+ ;
+
+/* RFC 2230 */
+rdata_kx: STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */
+ zadd_rdata_domain($3); /* exchanger */
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 2538 */
+rdata_cert: STR sp STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_certificate_type($1.str));
+ /* type */
+ zadd_rdata_wireformat(zparser_conv_short($3.str)); /* key tag */
+ zadd_rdata_wireformat(zparser_conv_algorithm($5.str));
+ /* algorithm */
+ zadd_rdata_wireformat(zparser_conv_b64($7.str));
+ /* certificate or CRL */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+/* RFC 3123 */
+rdata_apl: rdata_apl_seq trail
+ ;
+
+rdata_apl_seq: dotted_str
+ {
+ zadd_rdata_wireformat(zparser_conv_apl_rdata($1.str));
+
+ free($1.str);
+ }
+ | rdata_apl_seq sp dotted_str
+ {
+ zadd_rdata_wireformat(zparser_conv_apl_rdata($3.str));
+
+ free($3.str);
+ }
+ ;
+
+rdata_ds: STR sp STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* keytag */
+ zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* type */
+ zadd_rdata_wireformat(zparser_conv_hex($7.str, $7.len)); /* hash */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+rdata_dlv: STR sp STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* keytag */
+ zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* type */
+ zadd_rdata_wireformat(zparser_conv_hex($7.str, $7.len)); /* hash */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+rdata_sshfp: STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_byte($1.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_byte($3.str)); /* fp type */
+ zadd_rdata_wireformat(zparser_conv_hex($5.str, $5.len)); /* hash */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ }
+ ;
+
+rdata_dhcid: str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_b64($1.str)); /* data blob */
+
+ free($1.str);
+ }
+ ;
+
+rdata_rrsig: STR sp STR sp STR sp STR sp STR sp STR
+ sp STR sp wire_dname sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_rrtype($1.str));
+ /* rr covered */
+ zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* # labels */
+ zadd_rdata_wireformat(zparser_conv_period($7.str));
+ /* # orig TTL */
+ zadd_rdata_wireformat(zparser_conv_time($9.str)); /* sig exp */
+ zadd_rdata_wireformat(zparser_conv_time($11.str)); /* sig inc */
+ zadd_rdata_wireformat(zparser_conv_short($13.str)); /* key id */
+/* zadd_rdata_wireformat(zparser_conv_dns_name((const uint8_t*)
+ $15.str,
+ $15.len));*/
+ knot_dname_t *dname =
+ knot_dname_new_from_wire((uint8_t *)$15.str, $15.len, NULL);
+ if (dname == NULL) {
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ } else {
+ knot_dname_cat(dname, parser->root_domain);
+ }
+
+ zadd_rdata_domain(dname);
+ /* sig name */
+ zadd_rdata_wireformat(zparser_conv_b64($17.str)); /* sig data */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ free($9.str);
+ free($11.str);
+ free($13.str);
+ free($15.str);
+ free($17.str);
+ }
+ ;
+
+rdata_nsec: wire_dname nsec_seq
+ {
+/* zadd_rdata_wireformat(zparser_conv_dns_name((const uint8_t*)
+ $1.str,
+ $1.len));*/
+
+ knot_dname_t *dname =
+ knot_dname_new_from_wire((uint8_t *)$1.str, $1.len, NULL);
+
+ free($1.str);
+
+ knot_dname_cat(dname, parser->root_domain);
+
+ zadd_rdata_domain(dname);
+ /* nsec name */
+ zadd_rdata_wireformat(zparser_conv_nsec(nsecbits));
+ /* nsec bitlist */
+ memset(nsecbits, 0, sizeof(nsecbits));
+ nsec_highest_rcode = 0;
+ }
+ ;
+
+rdata_nsec3: STR sp STR sp STR sp STR sp STR nsec_seq
+ {
+#ifdef NSEC3
+ nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len);
+
+/* knot_dname_t *dname =
+ knot_dname_new_from_str($9.str, $9.len, NULL);
+
+ zadd_rdata_domain(dname); */
+
+ zadd_rdata_wireformat(zparser_conv_b32($9.str));
+ /* next hashed name */
+ zadd_rdata_wireformat(zparser_conv_nsec(nsecbits));
+ /* nsec bitlist */
+ memset(nsecbits, 0, sizeof(nsecbits));
+ nsec_highest_rcode = 0;
+#else
+ zc_error_prev_line("nsec3 not supported");
+#endif /* NSEC3 */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ free($9.str);
+ }
+ ;
+
+rdata_nsec3_param: STR sp STR sp STR sp STR trail
+ {
+#ifdef NSEC3
+ nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len);
+#else
+ zc_error_prev_line("nsec3 not supported");
+#endif /* NSEC3 */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+rdata_dnskey: STR sp STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* flags */
+ zadd_rdata_wireformat(zparser_conv_byte($3.str)); /* proto */
+ zadd_rdata_wireformat(zparser_conv_algorithm($5.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_b64($7.str)); /* hash */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+rdata_ipsec_base: STR sp STR sp STR sp dotted_str
+ {
+ knot_dname_t* name = 0;
+ zadd_rdata_wireformat(zparser_conv_byte($1.str)); /* precedence */
+ zadd_rdata_wireformat(zparser_conv_byte($3.str));
+ /* gateway type */
+ zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* algorithm */
+ switch(atoi($3.str)) {
+ case IPSECKEY_NOGATEWAY:
+ zadd_rdata_wireformat(alloc_rdata_init("", 0));
+ break;
+ case IPSECKEY_IP4:
+ zadd_rdata_wireformat(zparser_conv_a($7.str));
+ break;
+ case IPSECKEY_IP6:
+ zadd_rdata_wireformat(zparser_conv_aaaa($7.str));
+ break;
+ case IPSECKEY_DNAME:
+ /* convert and insert the dname */
+ if(strlen($7.str) == 0)
+ zc_error_prev_line("IPSECKEY must specify"
+ "gateway name");
+ name = knot_dname_new_from_wire((uint8_t*)$7.str + 1,
+ strlen($7.str + 1),
+ NULL);
+ if(!name) {
+ zc_error_prev_line("IPSECKEY bad gateway"
+ "dname %s", $7.str);
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ if($7.str[strlen($7.str)-1] != '.') {
+ knot_dname_t* tmpd =
+ knot_dname_new_from_wire(name->name,
+ name->size,
+ NULL);
+ if (tmpd == NULL) {
+ zc_error_prev_line("Could not create dname!");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ name = knot_dname_cat(tmpd,
+ knot_node_parent(parser->origin, 0)->owner);
+ }
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+
+ uint8_t* dncpy = malloc(sizeof(uint8_t) * name->size);
+ if (dncpy == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(dncpy, name->name, name->size);
+ zadd_rdata_wireformat((uint16_t *)dncpy);
+ //knot_dname_free(&name);
+ break;
+ default:
+ zc_error_prev_line("unknown IPSECKEY gateway type");
+ }
+ }
+ ;
+
+rdata_ipseckey: rdata_ipsec_base sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_b64($3.str)); /* public key */
+
+ free($3.str);
+ }
+ | rdata_ipsec_base trail
+ ;
+
+rdata_unknown: URR sp STR sp str_sp_seq trail
+ {
+ /* $2 is the number of octects, currently ignored */
+ $$ = zparser_conv_hex($5.str, $5.len);
+ free($5.str);
+ free($3.str);
+ }
+ | URR sp STR trail
+ {
+ $$ = zparser_conv_hex("", 0);
+ free($3.str);
+ }
+ | URR error NL
+ {
+ $$ = zparser_conv_hex("", 0);
+ }
+ ;
+%%
+
+int zp_wrap(void)
+{
+ return 1;
+}
+
+/*
+ * Create the parser.
+ */
+zparser_type *zparser_create()
+{
+ zparser_type *result = malloc(sizeof(zparser_type));
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ result->temporary_items = malloc(MAXRDATALEN *
+ sizeof(knot_rdata_item_t));
+ if (result->temporary_items == NULL) {
+ ERR_ALLOC_FAILED;
+ free(result);
+ return NULL;
+ }
+
+ result->current_rrset = knot_rrset_new(NULL, 0, 0, 0);
+ if (result->current_rrset == NULL) {
+ ERR_ALLOC_FAILED;
+ free(result->temporary_items);
+ free(result);
+ return NULL;
+ }
+
+ result->root_domain = knot_dname_new_from_str(".", 1, NULL);
+// printf("THE NEW ROOT: %p\n", result->root_domain);
+ if (result->root_domain == NULL) {
+ ERR_ALLOC_FAILED;
+ free(result->temporary_items);
+ free(result->current_rrset);
+ free(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+/*
+ * Initialize the parser for a new zone file.
+ */
+void
+zparser_init(const char *filename, uint32_t ttl, uint16_t rclass,
+ knot_node_t *origin, knot_dname_t *origin_from_config)
+{
+ memset(nxtbits, 0, sizeof(nxtbits));
+ memset(nsecbits, 0, sizeof(nsecbits));
+ nsec_highest_rcode = 0;
+
+ parser->current_zone = NULL;
+ parser->prev_dname = NULL;
+
+ parser->default_ttl = ttl;
+ parser->default_class = rclass;
+
+ parser->origin = origin;
+ parser->prev_dname = NULL;//parser->origin->owner;
+
+ parser->default_apex = origin;
+ parser->error_occurred = 0;
+ parser->errors = 0;
+ parser->line = 1;
+ parser->filename = filename;
+ parser->rdata_count = 0;
+ parser->origin_from_config = origin_from_config;
+
+ parser->last_node = origin;
+// parser->root_domain = NULL;
+
+ /* Create zone */
+ parser->current_zone = knot_zone_new(origin, 0, 1);
+
+ parser->node_rrsigs = NULL;
+ parser->rrsig_orphans = NULL;
+ parser->rrsig_orphan_count = 0;
+
+ parser->current_rrset->rclass = parser->default_class;
+ parser->current_rrset->rdata = NULL;
+}
+
+
+void zparser_free()
+{
+// knot_dname_release(parser->root_domain);
+// knot_dname_release(parser->prev_dname);
+ knot_dname_free(&parser->origin_from_config);
+ free(parser->temporary_items);
+ if (parser->current_rrset != NULL) {
+ free(parser->current_rrset);
+ }
+ free(parser);
+}
+
+void
+yyerror(void *scanner, const char *message)
+{
+ zc_error("%s", message);
+}
+
+static void
+error_va_list(unsigned line, const char *fmt, va_list args)
+{
+ if (parser->filename) {
+ fprintf(stderr, "%s:%u: ", parser->filename, line);
+ }
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+
+ ++parser->errors;
+ parser->error_occurred = 1;
+}
+
+/* the line counting sux, to say the least
+ * with this grose hack we try do give sane
+ * numbers back */
+void
+zc_error_prev_line(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ error_va_list(parser->line - 1, fmt, args);
+ va_end(args);
+}
+
+void
+zc_error(const char *fmt, ...)
+{
+ /* send an error message to stderr */
+ va_list args;
+ va_start(args, fmt);
+ error_va_list(parser->line, fmt, args);
+ va_end(args);
+}
+
+static void
+warning_va_list(unsigned line, const char *fmt, va_list args)
+{
+ if (parser->filename) {
+ fprintf(stderr, "%s:%u: ", parser->filename, line);
+ }
+ fprintf(stderr, "warning: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+}
+
+void
+zc_warning_prev_line(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ warning_va_list(parser->line - 1, fmt, args);
+ va_end(args);
+}
+
+void
+zc_warning(const char *fmt, ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ warning_va_list(parser->line, fmt, args);
+ va_end(args);
+}
+
+#ifdef NSEC3
+static void
+nsec3_add_params(const char* hashalgo_str, const char* flag_str,
+ const char* iter_str, const char* salt_str, int salt_len)
+{
+ zadd_rdata_wireformat(zparser_conv_byte(hashalgo_str));
+ zadd_rdata_wireformat(zparser_conv_byte(flag_str));
+ zadd_rdata_wireformat(zparser_conv_short(iter_str));
+
+ /* salt */
+ if(strcmp(salt_str, "-") != 0)
+ zadd_rdata_wireformat(zparser_conv_hex_length(salt_str,
+ salt_len));
+ else
+ zadd_rdata_wireformat(alloc_rdata_init("", 1));
+
+}
+#endif /* NSEC3 */
diff --git a/tests/querytcp.c b/tests/querytcp.c
new file mode 100644
index 0000000..7e1418f
--- /dev/null
+++ b/tests/querytcp.c
@@ -0,0 +1,797 @@
+/*
+TCP query version of queryperf
+querytcp.c
+ fujiwara@jprs.co.jp
+ 2009.08.12
+ version 0.4
+
+queryperf for tcp query
+
+This program measures DNS server performance of TCP query.
+
+o Running environment:
+ Development environment:
+ Linux
+ FreeBSD
+ MacOS X 10.3.4
+
+o How to make:
+ Linux: gcc -D_LINUX -Wall -O2 -g -lm -o querytcp querytcp.c
+ FreeBSD: gcc -Wall -O2 -g -lm -o querytcp querytcp.c
+ MacOS X: gcc -Wall -O2 -g -lm -lresolv -o querytcp querytcp.c
+
+o changes
+
+ 2010/6/7: Linux compatibility
+ 2009/8/12: Remove use of res_mkquery
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <netdb.h>
+#include <errno.h>
+#include <math.h>
+#include <err.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <math.h>
+#ifndef NO_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef __APPLE__
+#include <nameser8_compat.h>
+#endif
+
+#ifndef ns_t_soa
+#define ns_t_soa T_SOA
+#endif
+#ifndef ns_t_ns
+#define ns_t_ns T_NS
+#endif
+#ifndef ns_c_in
+#define ns_c_in C_IN
+#endif
+
+#ifdef NOINET6
+#undef AF_INET6
+#endif
+
+#define Global
+
+#ifndef PACKETSZ
+#define PACKETSZ 512
+#endif
+
+/* debug.c */
+void hexdump(char *title, unsigned char *memory, int len)
+{
+ printf("[ %s ", title);
+ while (len-- > 0)
+ printf("%02x ", *memory++);
+ printf("]\n");
+}
+
+#define Xmalloc(size) Xrealloc(NULL, size)
+
+void *Xrealloc(void *p, int size)
+{
+ int sz;
+
+ sz = (size > 0) ? size : -size;
+ if (p == NULL) {
+ p = malloc(sz);
+ } else {
+ p = realloc(p, sz);
+ }
+ if (p == NULL) {
+ char buf[100];
+ snprintf(buf, sizeof buf, "size=%d", size);
+ perror(buf);
+ exit(1);
+ }
+ if (size < 0)
+ memset(p, 0, sz);
+ return p;
+}
+
+/* strlcpy() emulation for Linux. */
+#ifdef _LINUX
+static inline size_t strlcpy(char *destination, const char *source, size_t size)
+{
+ if(strncpy(destination, source, size) == NULL)
+ return 0;
+
+ return size;
+}
+#endif
+
+/*
+ NULL ... returns NULL
+ */
+char *Xstrdup(char *p)
+{
+ char *q;
+ int len;
+
+ if (p == NULL)
+ return NULL;
+ len = strlen(p) + 1;
+ q = Xmalloc(len);
+ strlcpy(q, p, len);
+ return q;
+}
+
+
+typedef int64_t timediff_t;
+
+/* packet buffer */
+static struct timeval current;
+static struct timeval start, send_finished;;
+static fd_set fdset0r, fdset0w;
+static int nfds;
+static struct sockaddr_storage remote;
+static int remote_len = 0;
+static int finished = 0;
+static timediff_t Timeout = 10*1000000LL;
+unsigned short counter = 0;
+
+#define UpdateCurrentTime gettimeofday(&current, NULL)
+
+#define RECVBUFSIZ 65537
+#define SENDBUFSIZ 512
+
+struct dnsheader {
+ unsigned short id; // 2
+ unsigned char flag1, flag2; // 2
+ unsigned short qdcount, ancount, nscount, arcount; // 8
+};
+
+/*
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+*/
+
+struct queries {
+ struct tcpdns {
+ unsigned short len;
+ union {
+ struct dnsheader h;
+ unsigned char dnsdata[SENDBUFSIZ];
+ } u;
+ } send;
+ unsigned char recvbuf[RECVBUFSIZ];
+ int sendlen;
+ int sent_flag:1;
+ int tcpstate:2;
+ int fd;
+ int rpos;
+ int wpos;
+ int no;
+ struct timeval sent; /* long tv_sec, long tv_usec */
+};
+
+struct queries *Queries;
+
+#define NQUERY 100
+
+#define TCP_NONE 0
+#define TCP_WRITABLE 1
+#define TCP_READABLE 2
+
+/* input */
+char *ServerName = "127.0.0.1";
+char *ServerPort = "53";
+int family = PF_UNSPEC;
+char *datafile = NULL;
+int TimeLimit = 20;
+int EDNS0 = 0;
+int DNSSEC = 0;
+int recursion = 0;
+FILE *fp = NULL;
+int datafileloop = 0;
+int verbose = 0;
+int nQueries = 120;
+int printrcode = 0;
+char *rcodestr[]= {
+ "NOERROR", "FormatError", "ServerFailure", "NameError",
+ "NotImplemented", "Reused", "RCODE06", "RCODE07",
+ "RCODE08", "RCODE09", "RCODE10", "RCODE11",
+ "RCODE12", "RCODE13", "RCODE14", "RCODE15",
+};
+
+timediff_t timediff(struct timeval *a, struct timeval *b) /* u sec */
+{
+ return (a->tv_sec - b->tv_sec) * 1000000 + (a->tv_usec - b->tv_usec);
+}
+
+#define TIMEOUTERROR -10000
+#define ERROROFFSET -20000
+#define ERRZEROREAD -30000
+
+uint64_t countrcode[16];
+uint64_t response_size_sum = 0;
+uint64_t response_size_sum2 = 0;
+uint64_t countanswers = 0;
+uint64_t countqueries = 0;
+uint64_t countzeroread = 0;
+uint64_t counttimeout = 0;
+uint64_t counterror = 0;
+
+int response_size_min = 0;
+int response_size_max = 0;
+
+
+
+void register_response(struct queries *q, int timeout, char *note)
+{
+ u_char *p;
+ int size;
+ int rcode;
+ int id;
+
+ id = ntohs(q->send.u.h.id);
+ if (note == NULL)
+ note = "";
+ countqueries++;
+ if (timeout >= 0) {
+ p = q->recvbuf;
+ NS_GET16(size, p);
+ response_size_sum += size;
+ response_size_sum2 += size * size;
+ if (response_size_min == 0 || response_size_min > size)
+ response_size_min = size;
+ if (response_size_max == 0 || response_size_max < size)
+ response_size_max = size;
+ rcode = p[3] & 0x0f;
+ countrcode[rcode]++;
+ countanswers++;
+ if (verbose)
+ printf("recv response id=%d rcode=%d size=%d rtt=%d\n", id, rcode, size, timeout);
+ } else if (timeout == ERRZEROREAD) {
+ countzeroread++;
+ if (verbose)
+ printf("recv response id=%d zeroread\n", id);
+ } else if (timeout == TIMEOUTERROR) {
+ counttimeout++;
+ if (verbose)
+ printf("recv timeout id=%d %lld usec\n", id, timediff(&current, &q->sent));
+ } else {
+ counterror++;
+ if (verbose) {
+ printf("recv error id=%d errno=%d at %s (%s)\n", id, ERROROFFSET - timeout, note, strerror(errno));
+ }
+ }
+#ifdef DEBUG
+ printf("%ld.%03ld no=%d fd=%d %d %s\n", q->sent.tv_sec, q->sent.tv_usec/1000, q->no, q->fd, timeout, note);
+ fflush(stdout);
+#endif
+}
+
+void output()
+{
+ double response_size_average, response_size_variance, et;
+
+ et = ((double)timediff(&current, &start))/1000000.0;
+
+ printf("elapsed time: %.3f\n", et);
+ printf("tcp qps: %.3f\n", (double)countanswers/et);
+ printf("sent: %lld\n", countqueries);
+ printf("answer: %lld %3.1f%%\n", countanswers,
+ (double)((double)countanswers/(double)countqueries*100.0));
+ printf("error: %lld %3.1f%%\n", counterror,
+ (double)((double)counterror/(double)countqueries*100.0));
+ printf("zeroread: %lld %3.1f%%\n", countzeroread,
+ (double)((double)countzeroread/(double)countqueries*100.0));
+ printf("timeout: %lld %3.1f%%\n", counttimeout,
+ (double)((double)counttimeout/(double)countqueries*100.0));
+ response_size_average = (double)response_size_sum/countanswers;
+ response_size_variance = (double)response_size_sum2 / countanswers
+ - response_size_average * response_size_average;
+ printf("response size: %d/%.3f/%d/%.3f bytes\n", response_size_min, response_size_average, response_size_max, sqrt(response_size_variance));
+ if (printrcode) {
+ int i;
+ for (i = 0; i < 16; i++) {
+ if (countrcode[i] != 0) {
+ printf("%s %lld %5.1f\n", rcodestr[i], countrcode[i], ((double)countrcode[i])/((double)countanswers)*100.0);
+ }
+ }
+ }
+}
+
+void tcp_close(struct queries *q)
+{
+
+#ifdef DEBUG
+printf("tcp_close no=%d fd=%d\n", q->no, q->fd);
+#endif
+ if (q->fd >= 0) {
+ close(q->fd);
+ FD_CLR(q->fd, &fdset0r);
+ FD_CLR(q->fd, &fdset0w);
+ }
+ q->sent_flag = 0;
+ q->tcpstate = TCP_NONE;
+ q->fd = -1;
+}
+
+void tcp_send(struct queries *q)
+{
+ int len;
+
+ len = send(q->fd, &q->send, q->sendlen, MSG_NOSIGNAL);
+#ifdef DEBUG
+printf("tcp_send no=%d fd=%d %d:%d:%d\n", q->no, q->fd, len, q->wpos, q->sendlen);
+#endif
+ if (len < 0) {
+ if (errno == ENOTCONN) {
+printf("tcp_send no=%d fd=%d ENOTCONN return\n", q->no, q->fd);
+ return;
+ }
+ register_response(q, ERROROFFSET - errno, "tcp_send");
+ tcp_close(q);
+ return;
+ }
+ if (len != q->sendlen) {
+ register_response(q, ERROROFFSET - errno, "tcp_send:sendto");
+ tcp_close(q);
+ return;
+ }
+ FD_CLR(q->fd, &fdset0w);
+ FD_SET(q->fd, &fdset0r);
+}
+
+struct typecodes {
+ char *name;
+ int code;
+} typecodes[] = {
+ { "A", ns_t_a },
+ { "NS", ns_t_ns },
+ { "SOA", ns_t_soa },
+ { "PTR", ns_t_ptr },
+ { "HINFO", ns_t_hinfo },
+ { "MX", ns_t_mx },
+ { "TXT", ns_t_txt },
+ { "SIG", ns_t_sig },
+ { "KEY", ns_t_key },
+ { "AAAA", ns_t_aaaa },
+ { "NXT", ns_t_nxt },
+ { "SRV", ns_t_srv },
+ { "NAPTR", ns_t_naptr },
+ { NULL, -1 },
+};
+
+int stringtodname(unsigned char *qname, unsigned char *buff, unsigned char *lim)
+{
+ unsigned char *p, *s, *t;
+ int count, total;
+
+ t = qname;
+ p = buff;
+ total = 0;
+ for ( ;; ) {
+ s = p++;
+ count = 0;
+ if (p >= lim) return -1;
+ while (*t != 0 && *t != '.')
+ if (p < lim) {
+ *p++ = *t++;
+ count++;
+ } else
+ return -1;
+ *s = count;
+ if (count == 0)
+ break;
+ if (count > 63)
+ return -1;
+ total += count + 1;
+ if (*t == '.') t++;
+ }
+ if (total > 250 || !(*t == 0 || (*t == '.' && t[1] == 0)))
+ return -1;
+ return p - buff;
+}
+
+void send_query_error(char *mesg)
+{
+ err(1, "Packet size exceed: %s", mesg);
+}
+
+void send_query(struct queries *q)
+{
+ u_char *p, *lim;
+ char *qname;
+ int qclass;
+ int qtype;
+ int tmp;
+ struct typecodes *t = typecodes;
+ u_char buff[512];
+ static char sep[] = "\n\t ";
+ static int lineno = 0;
+
+ /*
+ SEND E[send_packet_pos]
+ */
+ if (q->sent_flag) {
+ register_response(q, TIMEOUTERROR, "send_query");
+ tcp_close(q);
+ }
+ if (fp == NULL) {
+ qname = "version.bind";
+ qclass = ns_c_chaos;
+ qtype = ns_t_txt;
+ } else {
+ do {
+ if (fgets((char*)buff, sizeof(char)*512, fp) == NULL) {
+ if (datafileloop == 1) {
+ finished = 1;
+ fclose(fp);
+ fp = NULL;
+ return;
+ }
+ if (datafileloop > 0)
+ datafileloop--;
+ rewind(fp);
+ lineno = 0;
+ if (fgets((char*)buff, sizeof(char)*512, fp) == NULL)
+ err(1, "cannot rewind input file");
+ }
+ lineno++;
+ } while(buff[0] == '#');
+ qname = strtok((char*)buff, sep);
+ p = (u_char*) strtok(NULL, sep);
+ if (p != NULL) {
+ while(t->name != NULL) {
+ if (!strcasecmp(t->name, (char*)p))
+ break;
+ t++;
+ }
+ qtype = t->code;
+ } else {
+ qtype = ns_t_a;
+ }
+ if (qname == NULL || qtype < 0)
+ err(1, "datafile format error at line %d, qname=%s qtype=%d", lineno, qname, qtype);
+ qclass = ns_c_in;
+ }
+ q->send.u.h.id = counter++;
+ q->send.u.h.flag1 = recursion ? 1 : 0; /* Query,OP=0,AA=0,TC=0,RD=0/1 */
+ q->send.u.h.flag2 = 0;
+ q->send.u.h.qdcount = htons(1);
+ q->send.u.h.ancount = 0;
+ q->send.u.h.nscount = 0;
+ q->send.u.h.arcount = 0;
+ p = q->send.u.dnsdata + sizeof(q->send.u.h);
+ lim = p + sizeof(q->send.u.dnsdata);
+ if ((tmp = stringtodname((u_char*) qname, p, lim)) < 0)
+ send_query_error(qname);
+ p += tmp;
+ *(unsigned short *)p = htons(qtype);
+ p += sizeof(unsigned short);
+ *(unsigned short *)p = htons(qclass);
+ p += sizeof(unsigned short);
+ q->sendlen = p - q->send.u.dnsdata;
+ if (EDNS0) {
+#define EDNS0size 11
+ if (q->sendlen + EDNS0size >= sizeof(q->send.u.dnsdata))
+ send_query_error("ENDS0");
+ *p++ = 0; /* . */
+ *(unsigned short *)p = htons(ns_t_opt);
+ p += 2;
+ *(unsigned short *)p = htons(4096);
+ p += 2;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = (DNSSEC == 0) ? 0 : 0x80; /* eflag: DO bit */
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ q->sendlen += EDNS0size;
+ p = (u_char*) &q->send.u.dnsdata;
+ q->send.u.h.ancount = htons(1);
+ }
+ q->send.len = htons(q->sendlen);
+ q->sendlen += sizeof(q->send.len);
+ q->wpos = 0;
+ q->rpos = 0;
+ q->sent = current;
+ if (verbose > 0) {
+ int id = ntohs(*(unsigned short *)&q->send.u.dnsdata);
+ printf("sending query(%s,%d,%d) id=%d %d bytes to %s\n", qname, qclass, qtype, id, q->sendlen, ServerName);
+ hexdump("sending packet header:", (unsigned char*) &q->send.u.h, 12);
+ }
+ if (q->fd > 0)
+ err(1, "q->fd > 0 but ignored\n");
+
+ q->fd = socket(remote.ss_family, SOCK_STREAM, 0);
+ tmp = fcntl(q->fd, F_GETFL, 0);
+ fcntl(q->fd, F_SETFL, O_NONBLOCK | tmp);
+ int conn_ret = connect(q->fd, (struct sockaddr *)&remote, remote_len);
+ if(conn_ret < 0 && errno != EINPROGRESS) {
+ register_response(q, ERROROFFSET - errno, "send_query:socket+fcntl+connect");
+ tcp_close(q);
+ return;
+ }
+#ifdef DEBUG
+printf("send_query no=%d fd=%d socket|connect\n", q->no, q->fd);
+#endif
+ q->tcpstate = TCP_WRITABLE;
+ FD_SET(q->fd, &fdset0w);
+ FD_CLR(q->fd, &fdset0r);
+ if (nfds <= q->fd) {
+ nfds = q->fd + 1;
+ }
+ q->sent = current;
+ q->sent_flag = 1;
+}
+
+int UpdateQuery()
+{
+ int i;
+ timediff_t t, min = Timeout;
+ struct queries *q;
+ int free = 0;
+
+ if (!finished && TimeLimit > 0) {
+ if ((t = timediff(&current, &start)) > TimeLimit * 1000000LL) {
+ finished = 1;
+ send_finished = current;
+ }
+ }
+ for(i = 0; i < nQueries; i++) {
+ q = &Queries[i];
+ if (q->sent_flag) {
+ if ((t = timediff(&current, &q->sent)) > Timeout) {
+ /* timeouted */
+ register_response(q, TIMEOUTERROR, "UpdateQuery");
+ tcp_close(q);
+ } else
+ if (t < min)
+ min = t;
+ }
+ if (!q->sent_flag) {
+ if (!finished)
+ send_query(q);
+ else
+ free++;
+ }
+ }
+ if (free == nQueries)
+ min = -1; /* finished */
+ return min;
+}
+
+char *skipname(char *p)
+{
+ while(*p > 0 && *p < 0x40) p += *p + 1;
+ if (*p == 0)
+ return p+1;
+ return p+2;
+}
+
+#define Hexdump(A,B,C)
+
+void tcp_receive(struct queries *q)
+{
+ int len, len2;
+ timediff_t tmp;
+ unsigned char *recvp;
+
+/*printf("tcp_receive %s\n", q->nameserverlabel);*/
+
+ len = read(q->fd, q->recvbuf + q->rpos, len2 = RECVBUFSIZ - q->rpos);
+ if (len < 0) {
+ if (errno == EAGAIN)
+ return;
+ register_response(q, ERROROFFSET - errno, "tcp_receive:read");
+ tcp_close(q);
+ return;
+ }
+ if (len == 0) {
+ register_response(q, ERRZEROREAD, "tcp_receive:read");
+ tcp_close(q);
+ return;
+ }
+ q->rpos += len;
+ if (q->rpos < 2)
+ return;
+ len2 = ntohs(*(unsigned short *)(q->recvbuf));
+ if (q->rpos >= len2 + 2) {
+ /* finished */
+ recvp = q->recvbuf + 2;
+ if (memcmp(recvp, q->send.u.dnsdata, 2) == 0) {
+ if ((recvp[2] & 1) == 0 /* RA bit */
+ || (recvp[3] & 15) != 0 /* RCODE must be 0 */
+ ) {
+/*
+ fprintf(stderr, "WRONG AA=%d RCODE=%d\n",
+ ((recvp[2]>>2) & 1), recvp[3]&15);
+*/
+ }
+ tmp = timediff(&current, &q->sent);
+ register_response(q, tmp, "tcp_receive");
+ tcp_close(q);
+ return;
+ } else {
+printf("no=%d fd=%d unknown recv %d bytes, len=%d\n", q->no, q->fd, q->rpos, ntohs(*(unsigned short *)(q->recvbuf)));
+ hexdump("", q->recvbuf, len);
+ /*
+ fprintf(stderr, "unknown recv from %s, %d bytes %02x %02x\n", q->nameserverlabel, q->rpos, recvp[0], recvp[1]);
+ */
+ tcp_close(q);
+ }
+ }
+}
+
+void query()
+{
+ fd_set fdsetr, fdsetw;
+ struct timeval timeout;
+ int min;
+ struct queries *q;
+ int i, n;
+ struct addrinfo hints, *res0;
+ int error;
+
+ Queries = Xmalloc(sizeof(Queries[0]) * nQueries);
+ memset(&remote, 0, sizeof(remote));
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ printf("resolving: %s:%s\n", ServerName, ServerPort);
+ error = getaddrinfo(ServerName, 0, &hints, &res0);
+ if (error) {
+ errx(1, "%s", gai_strerror(error));
+ }
+
+ /* Update server port. */
+ int port = atoi(ServerPort);
+ if (res0->ai_family == AF_INET6) {
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)res0->ai_addr;
+ ipv6->sin6_port = htons(port);
+ } else {
+ struct sockaddr_in *ipv4 = (struct sockaddr_in*)res0->ai_addr;
+ ipv4->sin_port = htons(port);
+ }
+
+ remote_len = res0->ai_addrlen;
+ memcpy(&remote, res0->ai_addr, res0->ai_addrlen);
+ memset(&countrcode, 0, sizeof(countrcode));
+
+ res_init();
+ _res.options ^= ~RES_RECURSE;
+ _res.options |= RES_AAONLY;
+
+ for (i = 0; i < nQueries; i++) {
+ Queries[i].sent_flag = 0;
+ Queries[i].no = i;
+ }
+
+ FD_ZERO(&fdset0r);
+ FD_ZERO(&fdset0w);
+ nfds = 0;
+ UpdateCurrentTime;
+ start = current;
+ finished = 0;
+
+ for (;;) {
+ UpdateCurrentTime;
+ if ((min = UpdateQuery()) < 0)
+ break;
+ timeout.tv_sec = min / 1000000;
+ timeout.tv_usec = min % 1000000;
+ fdsetr = fdset0r;
+ fdsetw = fdset0w;
+ n = select(nfds, &fdsetr, &fdsetw, NULL, &timeout);
+ UpdateCurrentTime;
+ for(i = 0; i < nQueries; i++) {
+ q = &Queries[i];
+ if (q->fd < 0 || !q->sent_flag)
+ continue;
+ if (FD_ISSET(q->fd, &fdsetw)) {
+ tcp_send(q);
+ } else if (FD_ISSET(q->fd, &fdsetr)) {
+ tcp_receive(q);
+ }
+ }
+ }
+}
+
+void usage()
+{
+ fprintf(stderr,
+"querytcp [-d datafile] [-s server_addr] [-p port] [-q num_queries] [-t timeout] [l limit] [-4] [-6] [-h]\n"
+" -d specifies the input data file (default: stdin)\n"
+" -s sets the server to query (default: 127.0.0.1)\n"
+" -p sets the port on which to query the server (default: 53)\n"
+" -q specifies the maximum number of queries outstanding (default: 120)\n"
+" -t specifies the timeout for query completion in seconds (default: 10)\n"
+" -l specifies how a limit for how long to run tests in seconds (no default)\n"
+" -e enable EDNS0\n"
+" -D set DO bit\n"
+" -r set RD bit\n"
+"\n"
+"\n"
+"\n"
+" -c print the number of packets with each rcode\n"
+" -v verbose: report the RCODE of each response on stdout\n"
+" -h print this usage\n"
+);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int ch, i;
+ printf("dnsheader size: %d\n", sizeof(struct dnsheader));
+ while ((ch = getopt(argc, argv, "d:s:p:q:t:l:46eDrvh")) != -1) {
+ switch (ch) {
+ case 'q':
+ nQueries = atoi(optarg);
+ if (nQueries < 1)
+ err(1, "-q requires natural number");
+ break;
+ case 'p':
+ ServerPort = Xstrdup(optarg);
+ break;
+ case 's':
+ ServerName = Xstrdup(optarg);
+ break;
+ case 'd':
+ datafile = Xstrdup(optarg);
+ if ((fp = fopen(datafile, "r")) == NULL)
+ err(1, "cannot open %s", optarg);
+ break;
+ case 't':
+ i = atoi(optarg);
+ if (i < 1)
+ err(1, "-t timeout > 0");
+ Timeout = (int64_t)i * 1000000LL;
+ break;
+ case 'l':
+ TimeLimit = atoi(optarg);
+ break;
+ case '4':
+ family = AF_INET;
+ break;
+ case '6':
+ family = AF_INET6;
+ break;
+ case 'e':
+ EDNS0 = 1;
+ break;
+ case 'D':
+ DNSSEC = 1;
+ break;
+ case 'r':
+ recursion = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'c':
+ printrcode = 1;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ query();
+ output();
+
+ return 0;
+}
diff --git a/ylwrap b/ylwrap
new file mode 100755
index 0000000..84d5634
--- /dev/null
+++ b/ylwrap
@@ -0,0 +1,222 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005,
+# 2007, 2009 Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case "$1" in
+ '')
+ echo "$0: No files given. Try \`$0 --help' for more information." 1>&2
+ exit 1
+ ;;
+ --basedir)
+ basedir=$2
+ shift 2
+ ;;
+ -h|--h*)
+ cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+ INPUT is the input file
+ OUTPUT is one file PROG generates
+ DESIRED is the file we actually want instead of OUTPUT
+ PROGRAM is program to run
+ ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v|--v*)
+ echo "ylwrap $scriptversion"
+ exit $?
+ ;;
+esac
+
+
+# The input.
+input="$1"
+shift
+case "$input" in
+ [\\/]* | ?:[\\/]*)
+ # Absolute path; do nothing.
+ ;;
+ *)
+ # Relative path. Make it absolute.
+ input="`pwd`/$input"
+ ;;
+esac
+
+pairlist=
+while test "$#" -ne 0; do
+ if test "$1" = "--"; then
+ shift
+ break
+ fi
+ pairlist="$pairlist $1"
+ shift
+done
+
+# The program to run.
+prog="$1"
+shift
+# Make any relative path in $prog absolute.
+case "$prog" in
+ [\\/]* | ?:[\\/]*) ;;
+ *[\\/]*) prog="`pwd`/$prog" ;;
+esac
+
+# FIXME: add hostname here for parallel makes that run commands on
+# other machines. But that might take us over the 14-char limit.
+dirname=ylwrap$$
+trap "cd '`pwd`'; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+ 0) "$prog" "$input" ;;
+ *) "$prog" "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+ set X $pairlist
+ shift
+ first=yes
+ # Since DOS filename conventions don't allow two dots,
+ # the DOS version of Bison writes out y_tab.c instead of y.tab.c
+ # and y_tab.h instead of y.tab.h. Test to see if this is the case.
+ y_tab_nodot="no"
+ if test -f y_tab.c || test -f y_tab.h; then
+ y_tab_nodot="yes"
+ fi
+
+ # The directory holding the input.
+ input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'`
+ # Quote $INPUT_DIR so we can use it in a regexp.
+ # FIXME: really we should care about more than `.' and `\'.
+ input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'`
+
+ while test "$#" -ne 0; do
+ from="$1"
+ # Handle y_tab.c and y_tab.h output by DOS
+ if test $y_tab_nodot = "yes"; then
+ if test $from = "y.tab.c"; then
+ from="y_tab.c"
+ else
+ if test $from = "y.tab.h"; then
+ from="y_tab.h"
+ fi
+ fi
+ fi
+ if test -f "$from"; then
+ # If $2 is an absolute path name, then just use that,
+ # otherwise prepend `../'.
+ case "$2" in
+ [\\/]* | ?:[\\/]*) target="$2";;
+ *) target="../$2";;
+ esac
+
+ # We do not want to overwrite a header file if it hasn't
+ # changed. This avoid useless recompilations. However the
+ # parser itself (the first file) should always be updated,
+ # because it is the destination of the .y.c rule in the
+ # Makefile. Divert the output of all other files to a temporary
+ # file so we can compare them to existing versions.
+ if test $first = no; then
+ realtarget="$target"
+ target="tmp-`echo $target | sed s/.*[\\/]//g`"
+ fi
+ # Edit out `#line' or `#' directives.
+ #
+ # We don't want the resulting debug information to point at
+ # an absolute srcdir; it is better for it to just mention the
+ # .y file with no path.
+ #
+ # We want to use the real output file name, not yy.lex.c for
+ # instance.
+ #
+ # We want the include guards to be adjusted too.
+ FROM=`echo "$from" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+ TARGET=`echo "$2" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+
+ sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \
+ -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$?
+
+ # Check whether header files must be updated.
+ if test $first = no; then
+ if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+ echo "$2" is unchanged
+ rm -f "$target"
+ else
+ echo updating "$2"
+ mv -f "$target" "$realtarget"
+ fi
+ fi
+ else
+ # A missing file is only an error for the first file. This
+ # is a blatant hack to let us support using "yacc -d". If -d
+ # is not specified, we don't want an error when the header
+ # file is "missing".
+ if test $first = yes; then
+ ret=1
+ fi
+ fi
+ shift
+ shift
+ first=no
+ done
+else
+ ret=$?
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End: